1/*
2 * Copyright (C) 2010-2021 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Corporation. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "WebPageProxy.h"
29
30#include "APIArray.h"
31#include "APIAttachment.h"
32#include "APIContentWorld.h"
33#include "APIContextMenuClient.h"
34#include "APIDictionary.h"
35#include "APIFindClient.h"
36#include "APIFindMatchesClient.h"
37#include "APIFormClient.h"
38#include "APIFrameInfo.h"
39#include "APIFullscreenClient.h"
40#include "APIGeometry.h"
41#include "APIHistoryClient.h"
42#include "APIHitTestResult.h"
43#include "APIIconLoadingClient.h"
44#include "APILegacyContextHistoryClient.h"
45#include "APILoaderClient.h"
46#include "APINavigation.h"
47#include "APINavigationAction.h"
48#include "APINavigationClient.h"
49#include "APINavigationResponse.h"
50#include "APIOpenPanelParameters.h"
51#include "APIPageConfiguration.h"
52#include "APIPolicyClient.h"
53#include "APIResourceLoadClient.h"
54#include "APISecurityOrigin.h"
55#include "APIUIClient.h"
56#include "APIURLRequest.h"
57#include "APIWebsitePolicies.h"
58#include "AuthenticationChallengeProxy.h"
59#include "AuthenticationDecisionListener.h"
60#include "AuthenticationManager.h"
61#include "AuthenticatorManager.h"
62#include "DownloadManager.h"
63#include "DownloadProxy.h"
64#include "DrawingAreaMessages.h"
65#include "DrawingAreaProxy.h"
66#include "EventDispatcherMessages.h"
67#include "FormDataReference.h"
68#include "FrameInfoData.h"
69#include "LegacyGlobalSettings.h"
70#include "LoadParameters.h"
71#include "Logging.h"
72#include "NativeWebGestureEvent.h"
73#include "NativeWebKeyboardEvent.h"
74#include "NativeWebMouseEvent.h"
75#include "NativeWebWheelEvent.h"
76#include "NavigationActionData.h"
77#include "NetworkProcessMessages.h"
78#include "NetworkProcessProxy.h"
79#include "NotificationPermissionRequest.h"
80#include "NotificationPermissionRequestManager.h"
81#include "OptionalCallbackID.h"
82#include "PageClient.h"
83#include "PluginInformation.h"
84#include "PluginProcessManager.h"
85#include "PrintInfo.h"
86#include "ProcessThrottler.h"
87#include "ProvisionalPageProxy.h"
88#include "SafeBrowsingWarning.h"
89#include "SharedBufferDataReference.h"
90#include "SpeechRecognitionPermissionManager.h"
91#include "SpeechRecognitionRemoteRealtimeMediaSource.h"
92#include "SpeechRecognitionRemoteRealtimeMediaSourceManager.h"
93#include "SyntheticEditingCommandType.h"
94#include "TextChecker.h"
95#include "TextCheckerState.h"
96#include "TextRecognitionUpdateResult.h"
97#include "URLSchemeTaskParameters.h"
98#include "UndoOrRedo.h"
99#include "UserMediaPermissionRequestProxy.h"
100#include "UserMediaProcessManager.h"
101#include "WKContextPrivate.h"
102#include "WebAutomationSession.h"
103#include "WebBackForwardCache.h"
104#include "WebBackForwardList.h"
105#include "WebBackForwardListCounts.h"
106#include "WebBackForwardListItem.h"
107#include "WebCertificateInfo.h"
108#include "WebContextMenuItem.h"
109#include "WebContextMenuProxy.h"
110#include "WebCoreArgumentCoders.h"
111#include "WebEditCommandProxy.h"
112#include "WebEventConversion.h"
113#include "WebFramePolicyListenerProxy.h"
114#include "WebFullScreenManagerProxy.h"
115#include "WebFullScreenManagerProxyMessages.h"
116#include "WebImage.h"
117#include "WebInspectorUIProxy.h"
118#include "WebInspectorUtilities.h"
119#include "WebKeyboardEvent.h"
120#include "WebNavigationDataStore.h"
121#include "WebNavigationState.h"
122#include "WebNotificationManagerProxy.h"
123#include "WebOpenPanelResultListenerProxy.h"
124#include "WebPage.h"
125#include "WebPageCreationParameters.h"
126#include "WebPageDebuggable.h"
127#include "WebPageGroup.h"
128#include "WebPageGroupData.h"
129#include "WebPageInspectorController.h"
130#include "WebPageMessages.h"
131#include "WebPageNetworkParameters.h"
132#include "WebPageProxyMessages.h"
133#include "WebPasteboardProxy.h"
134#include "WebPaymentCoordinatorProxy.h"
135#include "WebPopupItem.h"
136#include "WebPopupMenuProxy.h"
137#include "WebPreferences.h"
138#include "WebPreferencesKeys.h"
139#include "WebProcessMessages.h"
140#include "WebProcessPool.h"
141#include "WebProcessProxy.h"
142#include "WebProtectionSpace.h"
143#include "WebResourceLoadStatisticsStore.h"
144#include "WebURLSchemeHandler.h"
145#include "WebUserContentControllerProxy.h"
146#include "WebViewDidMoveToWindowObserver.h"
147#include "WebWheelEventCoalescer.h"
148#include "WebsiteDataStore.h"
149#include <WebCore/AppHighlight.h>
150#include <WebCore/BitmapImage.h>
151#include <WebCore/CompositionHighlight.h>
152#include <WebCore/CrossSiteNavigationDataTransfer.h>
153#include <WebCore/DOMPasteAccess.h>
154#include <WebCore/DeprecatedGlobalSettings.h>
155#include <WebCore/DiagnosticLoggingClient.h>
156#include <WebCore/DiagnosticLoggingKeys.h>
157#include <WebCore/DragController.h>
158#include <WebCore/DragData.h>
159#include <WebCore/ElementContext.h>
160#include <WebCore/EventNames.h>
161#include <WebCore/ExceptionDetails.h>
162#include <WebCore/FloatRect.h>
163#include <WebCore/FocusDirection.h>
164#include <WebCore/FontAttributeChanges.h>
165#include <WebCore/FrameLoader.h>
166#include <WebCore/GlobalFrameIdentifier.h>
167#include <WebCore/GlobalWindowIdentifier.h>
168#include <WebCore/LengthBox.h>
169#include <WebCore/MIMETypeRegistry.h>
170#include <WebCore/MediaStreamRequest.h>
171#include <WebCore/PerformanceLoggingClient.h>
172#include <WebCore/PlatformEvent.h>
173#include <WebCore/PrivateClickMeasurement.h>
174#include <WebCore/PublicSuffix.h>
175#include <WebCore/RenderEmbeddedObject.h>
176#include <WebCore/ResourceLoadStatistics.h>
177#include <WebCore/RuntimeApplicationChecks.h>
178#include <WebCore/RuntimeEnabledFeatures.h>
179#include <WebCore/SSLKeyGenerator.h>
180#include <WebCore/SerializedCryptoKeyWrap.h>
181#include <WebCore/ShareData.h>
182#include <WebCore/SharedBuffer.h>
183#include <WebCore/ShouldTreatAsContinuingLoad.h>
184#include <WebCore/StoredCredentialsPolicy.h>
185#include <WebCore/TextCheckerClient.h>
186#include <WebCore/TextIndicator.h>
187#include <WebCore/ValidationBubble.h>
188#include <WebCore/WindowFeatures.h>
189#include <WebCore/WritingDirection.h>
190#include <stdio.h>
191#include <wtf/CallbackAggregator.h>
192#include <wtf/NeverDestroyed.h>
193#include <wtf/Scope.h>
194#include <wtf/SystemTracing.h>
195#include <wtf/URL.h>
196#include <wtf/URLParser.h>
197#include <wtf/WeakPtr.h>
198#include <wtf/text/StringView.h>
199#include <wtf/text/TextStream.h>
200
201#if ENABLE(APPLICATION_MANIFEST)
202#include "APIApplicationManifest.h"
203#endif
204
205#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
206#include "RemoteScrollingCoordinatorProxy.h"
207#endif
208
209#ifndef NDEBUG
210#include <wtf/RefCountedLeakCounter.h>
211#endif
212
213#if PLATFORM(COCOA)
214#include "InsertTextOptions.h"
215#include "QuickLookPreviewActivity.h"
216#include "RemoteLayerTreeDrawingAreaProxy.h"
217#include "RemoteLayerTreeScrollingPerformanceData.h"
218#include "UserMediaCaptureManagerProxy.h"
219#include "VideoFullscreenManagerProxy.h"
220#include "VideoFullscreenManagerProxyMessages.h"
221#include <WebCore/AttributedString.h>
222#include <WebCore/RunLoopObserver.h>
223#include <WebCore/SystemBattery.h>
224#include <WebCore/VersionChecks.h>
225#include <wtf/MachSendRight.h>
226#include <wtf/cocoa/Entitlements.h>
227#endif
228
229#if PLATFORM(MAC)
230#include "DisplayLink.h"
231#include <WebCore/ImageUtilities.h>
232#include <WebCore/UTIUtilities.h>
233#endif
234
235#if HAVE(TOUCH_BAR)
236#include "TouchBarMenuData.h"
237#include "TouchBarMenuItemData.h"
238#endif
239
240#if PLATFORM(COCOA) || PLATFORM(GTK)
241#include "ViewSnapshotStore.h"
242#endif
243
244#if PLATFORM(GTK)
245#include <WebCore/SelectionData.h>
246#endif
247
248#if USE(CAIRO)
249#include <WebCore/CairoUtilities.h>
250#endif
251
252#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
253#include <WebCore/MediaPlaybackTarget.h>
254#include <WebCore/WebMediaSessionManager.h>
255#endif
256
257#if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
258#include "PlaybackSessionManagerProxy.h"
259#endif
260
261#if ENABLE(WEB_AUTHN)
262#include "WebAuthenticatorCoordinatorProxy.h"
263#endif
264
265#if ENABLE(REMOTE_INSPECTOR)
266#include <JavaScriptCore/RemoteInspector.h>
267#endif
268
269#if HAVE(SEC_KEY_PROXY)
270#include "SecKeyProxyStore.h"
271#endif
272
273#if HAVE(APP_SSO)
274#include "SOAuthorizationCoordinator.h"
275#endif
276
277#if USE(DIRECT2D)
278#include <d3d11_1.h>
279#endif
280
281#if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
282#include "WebDeviceOrientationUpdateProviderProxy.h"
283#endif
284
285#if ENABLE(DATA_DETECTION)
286#include "DataDetectionResult.h"
287#endif
288
289#if ENABLE(MEDIA_USAGE)
290#include "MediaUsageManager.h"
291#endif
292
293#if PLATFORM(COCOA)
294#include "DefaultWebBrowserChecks.h"
295#endif
296
297#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
298#include "WebDateTimePicker.h"
299#endif
300
301#if ENABLE(MEDIA_SESSION_COORDINATOR)
302#include "MediaSessionCoordinatorProxyPrivate.h"
303#include "RemoteMediaSessionCoordinatorProxy.h"
304#endif
305
306#if HAVE(GROUP_ACTIVITIES)
307#include "GroupActivitiesSessionNotifier.h"
308#endif
309
310#if ENABLE(APP_HIGHLIGHTS)
311#include <WebCore/HighlightVisibility.h>
312#endif
313
314// This controls what strategy we use for mouse wheel coalescing.
315#define MERGE_WHEEL_EVENTS 1
316
317#define MESSAGE_CHECK(process, assertion) MESSAGE_CHECK_BASE(assertion, process->connection())
318#define MESSAGE_CHECK_URL(process, url) MESSAGE_CHECK_BASE(checkURLReceivedFromCurrentOrPreviousWebProcess(process, url), process->connection())
319#define MESSAGE_CHECK_COMPLETION(process, assertion, completion) MESSAGE_CHECK_COMPLETION_BASE(assertion, process->connection(), completion)
320
321#define WEBPAGEPROXY_RELEASE_LOG(channel, fmt, ...) RELEASE_LOG(channel, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", PID=%i] WebPageProxy::" fmt, this, m_identifier.toUInt64(), m_webPageID.toUInt64(), m_process->processIdentifier(), ##__VA_ARGS__)
322#define WEBPAGEPROXY_RELEASE_LOG_ERROR(channel, fmt, ...) RELEASE_LOG_ERROR(channel, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", PID=%i] WebPageProxy::" fmt, this, m_identifier.toUInt64(), m_webPageID.toUInt64(), m_process->processIdentifier(), ##__VA_ARGS__)
323
324// Represents the number of wheel events we can hold in the queue before we start pushing them preemptively.
325static const unsigned wheelEventQueueSizeThreshold = 10;
326
327static const Seconds resetRecentCrashCountDelay = 30_s;
328static unsigned maximumWebProcessRelaunchAttempts = 1;
329static const Seconds audibleActivityClearDelay = 10_s;
330static const Seconds tryCloseTimeoutDelay = 50_ms;
331
332namespace WebKit {
333using namespace WebCore;
334
335DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy"));
336
337class StorageRequests {
338 WTF_MAKE_NONCOPYABLE(StorageRequests); WTF_MAKE_FAST_ALLOCATED;
339 friend NeverDestroyed<StorageRequests>;
340public:
341 static StorageRequests& singleton();
342
343 void processOrAppend(CompletionHandler<void()>&& completionHandler)
344 {
345 if (m_requestsAreBeingProcessed) {
346 m_requests.append(WTFMove(completionHandler));
347 return;
348 }
349 m_requestsAreBeingProcessed = true;
350 completionHandler();
351 }
352
353 void processNextIfAny()
354 {
355 if (m_requests.isEmpty()) {
356 m_requestsAreBeingProcessed = false;
357 return;
358 }
359 m_requests.takeFirst()();
360 }
361
362private:
363 StorageRequests() { }
364 ~StorageRequests() { }
365
366 Deque<CompletionHandler<void()>> m_requests;
367 bool m_requestsAreBeingProcessed { false };
368};
369
370StorageRequests& StorageRequests::singleton()
371{
372 static NeverDestroyed<StorageRequests> requests;
373 return requests;
374}
375
376#if !LOG_DISABLED
377static const char* webMouseEventTypeString(WebEvent::Type type)
378{
379 switch (type) {
380 case WebEvent::MouseDown:
381 return "MouseDown";
382 case WebEvent::MouseUp:
383 return "MouseUp";
384 case WebEvent::MouseMove:
385 return "MouseMove";
386 case WebEvent::MouseForceChanged:
387 return "MouseForceChanged";
388 case WebEvent::MouseForceDown:
389 return "MouseForceDown";
390 case WebEvent::MouseForceUp:
391 return "MouseForceUp";
392 default:
393 ASSERT_NOT_REACHED();
394 return "<unknown>";
395 }
396}
397
398static const char* webKeyboardEventTypeString(WebEvent::Type type)
399{
400 switch (type) {
401 case WebEvent::KeyDown:
402 return "KeyDown";
403 case WebEvent::KeyUp:
404 return "KeyUp";
405 case WebEvent::RawKeyDown:
406 return "RawKeyDown";
407 case WebEvent::Char:
408 return "Char";
409 default:
410 ASSERT_NOT_REACHED();
411 return "<unknown>";
412 }
413}
414#endif // !LOG_DISABLED
415
416class PageClientProtector {
417 WTF_MAKE_NONCOPYABLE(PageClientProtector);
418public:
419 PageClientProtector(PageClient& pageClient)
420 : m_pageClient(makeWeakPtr(pageClient))
421 {
422 m_pageClient->refView();
423 }
424
425 ~PageClientProtector()
426 {
427 ASSERT(m_pageClient);
428 m_pageClient->derefView();
429 }
430
431private:
432 WeakPtr<PageClient> m_pageClient;
433};
434
435void WebPageProxy::forMostVisibleWebPageIfAny(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(WebPageProxy*)>&& completionHandler)
436{
437 // FIXME: If not finding right away a visible page, we might want to try again for a given period of time when there is a change of visibility.
438 WebPageProxy* selectedPage = nullptr;
439 WebProcessProxy::forWebPagesWithOrigin(sessionID, origin, [&](auto& page) {
440 if (!page.mainFrame())
441 return;
442 if (page.isViewVisible() && (!selectedPage || !selectedPage->isViewVisible())) {
443 selectedPage = &page;
444 return;
445 }
446 if (page.isViewFocused() && (!selectedPage || !selectedPage->isViewFocused())) {
447 selectedPage = &page;
448 return;
449 }
450 });
451 completionHandler(selectedPage);
452}
453
454Ref<WebPageProxy> WebPageProxy::create(PageClient& pageClient, WebProcessProxy& process, Ref<API::PageConfiguration>&& configuration)
455{
456 return adoptRef(*new WebPageProxy(pageClient, process, WTFMove(configuration)));
457}
458
459WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, Ref<API::PageConfiguration>&& configuration)
460 : m_identifier(Identifier::generate())
461 , m_webPageID(PageIdentifier::generate())
462 , m_pageClient(makeWeakPtr(pageClient))
463 , m_configuration(WTFMove(configuration))
464 , m_navigationClient(makeUniqueRef<API::NavigationClient>())
465 , m_historyClient(makeUniqueRef<API::HistoryClient>())
466 , m_iconLoadingClient(makeUnique<API::IconLoadingClient>())
467 , m_formClient(makeUnique<API::FormClient>())
468 , m_uiClient(makeUnique<API::UIClient>())
469 , m_findClient(makeUnique<API::FindClient>())
470 , m_findMatchesClient(makeUnique<API::FindMatchesClient>())
471#if ENABLE(CONTEXT_MENUS)
472 , m_contextMenuClient(makeUnique<API::ContextMenuClient>())
473#endif
474 , m_navigationState(makeUnique<WebNavigationState>())
475 , m_process(process)
476 , m_pageGroup(*m_configuration->pageGroup())
477 , m_preferences(*m_configuration->preferences())
478 , m_userContentController(*m_configuration->userContentController())
479 , m_visitedLinkStore(*m_configuration->visitedLinkStore())
480 , m_websiteDataStore(*m_configuration->websiteDataStore())
481 , m_userAgent(standardUserAgent())
482 , m_overrideContentSecurityPolicy { m_configuration->overrideContentSecurityPolicy() }
483#if ENABLE(FULLSCREEN_API)
484 , m_fullscreenClient(makeUnique<API::FullscreenClient>())
485#endif
486 , m_geolocationPermissionRequestManager(*this)
487#if PLATFORM(IOS_FAMILY)
488 , m_audibleActivityTimer(RunLoop::main(), this, &WebPageProxy::clearAudibleActivity)
489#endif
490 , m_initialCapitalizationEnabled(m_configuration->initialCapitalizationEnabled())
491 , m_cpuLimit(m_configuration->cpuLimit())
492 , m_backForwardList(WebBackForwardList::create(*this))
493 , m_waitsForPaintAfterViewDidMoveToWindow(m_configuration->waitsForPaintAfterViewDidMoveToWindow())
494 , m_hasRunningProcess(process.state() != WebProcessProxy::State::Terminated)
495#if HAVE(CVDISPLAYLINK)
496 , m_wheelEventActivityHysteresis([this](PAL::HysteresisState state) { wheelEventHysteresisUpdated(state); })
497#endif
498 , m_controlledByAutomation(m_configuration->isControlledByAutomation())
499#if PLATFORM(COCOA)
500 , m_isSmartInsertDeleteEnabled(TextChecker::isSmartInsertDeleteEnabled())
501#endif
502 , m_pageLoadState(*this)
503 , m_updateReportedMediaCaptureStateTimer(RunLoop::main(), this, &WebPageProxy::updateReportedMediaCaptureState)
504 , m_inspectorController(makeUnique<WebPageInspectorController>(*this))
505#if ENABLE(REMOTE_INSPECTOR)
506 , m_inspectorDebuggable(makeUnique<WebPageDebuggable>(*this))
507#endif
508 , m_resetRecentCrashCountTimer(RunLoop::main(), this, &WebPageProxy::resetRecentCrashCount)
509 , m_tryCloseTimeoutTimer(RunLoop::main(), this, &WebPageProxy::tryCloseTimedOut)
510 , m_corsDisablingPatterns(m_configuration->corsDisablingPatterns())
511#if ENABLE(APP_BOUND_DOMAINS)
512 , m_ignoresAppBoundDomains(m_configuration->ignoresAppBoundDomains())
513 , m_limitsNavigationsToAppBoundDomains(m_configuration->limitsNavigationsToAppBoundDomains())
514#endif
515{
516 WEBPAGEPROXY_RELEASE_LOG(Loading, "constructor:");
517
518 if (!m_configuration->drawsBackground())
519 m_backgroundColor = Color(Color::transparentBlack);
520
521 updateActivityState();
522 updateThrottleState();
523 updateHiddenPageThrottlingAutoIncreases();
524
525#if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
526 m_layerHostingMode = m_activityState & ActivityState::IsInWindow ? WebPageProxy::pageClient().viewLayerHostingMode() : LayerHostingMode::OutOfProcess;
527#endif
528
529 platformInitialize();
530
531#ifndef NDEBUG
532 webPageProxyCounter.increment();
533#endif
534
535 WebProcessPool::statistics().wkPageCount++;
536
537 m_preferences->addPage(*this);
538 m_pageGroup->addPage(*this);
539
540 m_inspector = WebInspectorUIProxy::create(*this);
541
542 if (hasRunningProcess())
543 didAttachToRunningProcess();
544
545 m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID, *this);
546
547#if PLATFORM(IOS_FAMILY)
548 DeprecatedGlobalSettings::setDisableScreenSizeOverride(m_preferences->disableScreenSizeOverride());
549
550 if (m_configuration->preferences()->serviceWorkerEntitlementDisabledForTesting())
551 disableServiceWorkerEntitlementInNetworkProcess();
552#endif
553
554#if PLATFORM(COCOA)
555 m_activityStateChangeDispatcher = makeUnique<RunLoopObserver>(static_cast<CFIndex>(RunLoopObserver::WellKnownRunLoopOrders::ActivityStateChange), [this] {
556 this->dispatchActivityStateChange();
557 });
558#endif
559
560#if ENABLE(REMOTE_INSPECTOR)
561 m_inspectorDebuggable->setRemoteDebuggingAllowed(true);
562 m_inspectorDebuggable->init();
563#endif
564 m_inspectorController->init();
565
566#if ENABLE(IPC_TESTING_API)
567 if (m_preferences->ipcTestingAPIEnabled())
568 process.setIgnoreInvalidMessageForTesting();
569#endif
570
571#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
572 GroupActivitiesSessionNotifier::sharedNotifier().addWebPage(*this);
573#endif
574}
575
576WebPageProxy::~WebPageProxy()
577{
578 WEBPAGEPROXY_RELEASE_LOG(Loading, "destructor:");
579
580 ASSERT(m_process->webPage(m_identifier) != this);
581#if ASSERT_ENABLED
582 for (WebPageProxy* page : m_process->pages())
583 ASSERT(page != this);
584#endif
585
586 setPageLoadStateObserver(nullptr);
587
588 if (!m_isClosed)
589 close();
590
591 WebProcessPool::statistics().wkPageCount--;
592
593 if (m_spellDocumentTag)
594 TextChecker::closeSpellDocumentWithTag(m_spellDocumentTag.value());
595
596 m_preferences->removePage(*this);
597 m_pageGroup->removePage(*this);
598
599#ifndef NDEBUG
600 webPageProxyCounter.decrement();
601#endif
602
603#if PLATFORM(MACCATALYST)
604 EndowmentStateTracker::singleton().removeClient(*this);
605#endif
606
607 for (auto& callback : m_nextActivityStateChangeCallbacks)
608 callback();
609
610 websiteDataStore().networkProcess().send(Messages::NetworkProcess::RemoveWebPageNetworkParameters(sessionID(), m_identifier), 0);
611
612#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
613 GroupActivitiesSessionNotifier::sharedNotifier().removeWebPage(*this);
614#endif
615}
616
617// FIXME: Should return a const PageClient& and add a separate non-const
618// version of this function, but several PageClient methods will need to become
619// const for this to be possible.
620PageClient& WebPageProxy::pageClient() const
621{
622 ASSERT(m_pageClient);
623 return *m_pageClient;
624}
625
626PAL::SessionID WebPageProxy::sessionID() const
627{
628 return m_websiteDataStore->sessionID();
629}
630
631DrawingAreaProxy* WebPageProxy::provisionalDrawingArea() const
632{
633 if (m_provisionalPage && m_provisionalPage->drawingArea())
634 return m_provisionalPage->drawingArea();
635 return drawingArea();
636}
637
638const API::PageConfiguration& WebPageProxy::configuration() const
639{
640 return m_configuration.get();
641}
642
643ProcessID WebPageProxy::processIdentifier() const
644{
645 if (m_isClosed)
646 return 0;
647
648 return m_process->processIdentifier();
649}
650
651bool WebPageProxy::hasRunningProcess() const
652{
653 // A page that has been explicitly closed is never valid.
654 if (m_isClosed)
655 return false;
656
657 return m_hasRunningProcess;
658}
659
660void WebPageProxy::notifyProcessPoolToPrewarm()
661{
662 m_process->processPool().didReachGoodTimeToPrewarm();
663}
664
665void WebPageProxy::setPreferences(WebPreferences& preferences)
666{
667 if (&preferences == m_preferences.ptr())
668 return;
669
670 m_preferences->removePage(*this);
671 m_preferences = preferences;
672 m_preferences->addPage(*this);
673
674 preferencesDidChange();
675}
676
677void WebPageProxy::setHistoryClient(UniqueRef<API::HistoryClient>&& historyClient)
678{
679 m_historyClient = WTFMove(historyClient);
680}
681
682void WebPageProxy::setNavigationClient(UniqueRef<API::NavigationClient>&& navigationClient)
683{
684 m_navigationClient = WTFMove(navigationClient);
685}
686
687void WebPageProxy::setLoaderClient(std::unique_ptr<API::LoaderClient>&& loaderClient)
688{
689 m_loaderClient = WTFMove(loaderClient);
690}
691
692void WebPageProxy::setPolicyClient(std::unique_ptr<API::PolicyClient>&& policyClient)
693{
694 m_policyClient = WTFMove(policyClient);
695}
696
697void WebPageProxy::setFormClient(std::unique_ptr<API::FormClient>&& formClient)
698{
699 if (!formClient) {
700 m_formClient = makeUnique<API::FormClient>();
701 return;
702 }
703
704 m_formClient = WTFMove(formClient);
705}
706
707void WebPageProxy::setUIClient(std::unique_ptr<API::UIClient>&& uiClient)
708{
709 if (!uiClient) {
710 m_uiClient = makeUnique<API::UIClient>();
711 return;
712 }
713
714 m_uiClient = WTFMove(uiClient);
715
716 if (hasRunningProcess())
717 send(Messages::WebPage::SetCanRunBeforeUnloadConfirmPanel(m_uiClient->canRunBeforeUnloadConfirmPanel()));
718
719 setCanRunModal(m_uiClient->canRunModal());
720 setNeedsFontAttributes(m_uiClient->needsFontAttributes());
721}
722
723void WebPageProxy::setIconLoadingClient(std::unique_ptr<API::IconLoadingClient>&& iconLoadingClient)
724{
725 bool hasClient = iconLoadingClient.get();
726 if (!iconLoadingClient)
727 m_iconLoadingClient = makeUnique<API::IconLoadingClient>();
728 else
729 m_iconLoadingClient = WTFMove(iconLoadingClient);
730
731 if (!hasRunningProcess())
732 return;
733
734 send(Messages::WebPage::SetUseIconLoadingClient(hasClient));
735}
736
737void WebPageProxy::setPageLoadStateObserver(std::unique_ptr<PageLoadState::Observer>&& observer)
738{
739 if (m_pageLoadStateObserver)
740 pageLoadState().removeObserver(*m_pageLoadStateObserver);
741 m_pageLoadStateObserver = WTFMove(observer);
742 if (m_pageLoadStateObserver)
743 pageLoadState().addObserver(*m_pageLoadStateObserver);
744}
745
746void WebPageProxy::setFindClient(std::unique_ptr<API::FindClient>&& findClient)
747{
748 if (!findClient) {
749 m_findClient = makeUnique<API::FindClient>();
750 return;
751 }
752
753 m_findClient = WTFMove(findClient);
754}
755
756void WebPageProxy::setFindMatchesClient(std::unique_ptr<API::FindMatchesClient>&& findMatchesClient)
757{
758 if (!findMatchesClient) {
759 m_findMatchesClient = makeUnique<API::FindMatchesClient>();
760 return;
761 }
762
763 m_findMatchesClient = WTFMove(findMatchesClient);
764}
765
766void WebPageProxy::setDiagnosticLoggingClient(std::unique_ptr<API::DiagnosticLoggingClient>&& diagnosticLoggingClient)
767{
768 m_diagnosticLoggingClient = WTFMove(diagnosticLoggingClient);
769}
770
771#if ENABLE(CONTEXT_MENUS)
772void WebPageProxy::setContextMenuClient(std::unique_ptr<API::ContextMenuClient>&& contextMenuClient)
773{
774 if (!contextMenuClient) {
775 m_contextMenuClient = makeUnique<API::ContextMenuClient>();
776 return;
777 }
778
779 m_contextMenuClient = WTFMove(contextMenuClient);
780}
781#endif
782
783void WebPageProxy::setInjectedBundleClient(const WKPageInjectedBundleClientBase* client)
784{
785 if (!client) {
786 m_injectedBundleClient = nullptr;
787 return;
788 }
789
790 m_injectedBundleClient = makeUnique<WebPageInjectedBundleClient>();
791 m_injectedBundleClient->initialize(client);
792}
793
794void WebPageProxy::setResourceLoadClient(std::unique_ptr<API::ResourceLoadClient>&& client)
795{
796 bool hadResourceLoadClient = !!m_resourceLoadClient;
797 m_resourceLoadClient = WTFMove(client);
798 bool hasResourceLoadClient = !!m_resourceLoadClient;
799 if (hadResourceLoadClient != hasResourceLoadClient)
800 send(Messages::WebPage::SetHasResourceLoadClient(hasResourceLoadClient));
801}
802
803void WebPageProxy::handleMessage(IPC::Connection& connection, const String& messageName, const WebKit::UserData& messageBody)
804{
805 ASSERT(m_process->connection() == &connection);
806
807 if (!m_injectedBundleClient)
808 return;
809
810 m_injectedBundleClient->didReceiveMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get());
811}
812
813void WebPageProxy::handleSynchronousMessage(IPC::Connection& connection, const String& messageName, const UserData& messageBody, CompletionHandler<void(UserData&&)>&& completionHandler)
814{
815 ASSERT(m_process->connection() == &connection);
816
817 if (!m_injectedBundleClient)
818 return completionHandler({ });
819
820 RefPtr<API::Object> returnData;
821 m_injectedBundleClient->didReceiveSynchronousMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get(), [completionHandler = WTFMove(completionHandler), process = m_process] (RefPtr<API::Object>&& returnData) mutable {
822 completionHandler(UserData(process->transformObjectsToHandles(returnData.get())));
823 });
824}
825
826void WebPageProxy::launchProcess(const RegistrableDomain& registrableDomain, ProcessLaunchReason reason)
827{
828 ASSERT(!m_isClosed);
829 ASSERT(!hasRunningProcess());
830
831 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcess:");
832
833 // In case we are currently connected to the dummy process, we need to make sure the inspector proxy
834 // disconnects from the dummy process first.
835 m_inspector->reset();
836
837 m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
838 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
839
840 auto& processPool = m_process->processPool();
841
842 auto* relatedPage = m_configuration->relatedPage();
843 if (relatedPage && !relatedPage->isClosed())
844 m_process = relatedPage->ensureRunningProcess();
845 else
846 m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), this, registrableDomain);
847 m_hasRunningProcess = true;
848
849 m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::Yes);
850 m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID, *this);
851
852#if ENABLE(IPC_TESTING_API)
853 if (m_preferences->store().getBoolValueForKey(WebPreferencesKey::ipcTestingAPIEnabledKey()))
854 m_process->setIgnoreInvalidMessageForTesting();
855#endif
856
857 finishAttachingToWebProcess(reason);
858
859 auto pendingInjectedBundleMessage = WTFMove(m_pendingInjectedBundleMessages);
860 for (auto& message : pendingInjectedBundleMessage)
861 send(Messages::WebPage::PostInjectedBundleMessage(message.messageName, UserData(process().transformObjectsToHandles(message.messageBody.get()).get())));
862}
863
864bool WebPageProxy::suspendCurrentPageIfPossible(API::Navigation& navigation, std::optional<FrameIdentifier> mainFrameID, ProcessSwapRequestedByClient processSwapRequestedByClient, ShouldDelayClosingUntilFirstLayerFlush shouldDelayClosingUntilFirstLayerFlush)
865{
866 m_suspendedPageKeptToPreventFlashing = nullptr;
867 m_lastSuspendedPage = nullptr;
868
869 if (!mainFrameID)
870 return false;
871
872 if (!hasCommittedAnyProvisionalLoads()) {
873 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because has not committed any load yet", m_process->processIdentifier());
874 return false;
875 }
876
877 if (isPageOpenedByDOMShowingInitialEmptyDocument()) {
878 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because it is showing the initial empty document", m_process->processIdentifier());
879 return false;
880 }
881
882 auto* fromItem = navigation.fromItem();
883
884 // If the source and the destination back / forward list items are the same, then this is a client-side redirect. In this case,
885 // there is no need to suspend the previous page as there will be no way to get back to it.
886 if (fromItem && fromItem == m_backForwardList->currentItem()) {
887 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because this is a client-side redirect", m_process->processIdentifier());
888 return false;
889 }
890
891 if (fromItem && fromItem->url() != pageLoadState().url()) {
892 WEBPAGEPROXY_RELEASE_LOG_ERROR(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because fromItem's URL does not match the page URL.", m_process->processIdentifier());
893 return false;
894 }
895
896 bool needsSuspendedPageToPreventFlashing = shouldDelayClosingUntilFirstLayerFlush == ShouldDelayClosingUntilFirstLayerFlush::Yes;
897 if (!needsSuspendedPageToPreventFlashing && (!fromItem || !shouldUseBackForwardCache())) {
898 if (!fromItem)
899 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i there is no associated WebBackForwardListItem", m_process->processIdentifier());
900 else
901 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i the back / forward cache is disabled", m_process->processIdentifier());
902 return false;
903 }
904
905 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Suspending current page for process pid %i", m_process->processIdentifier());
906 auto suspendedPage = makeUnique<SuspendedPageProxy>(*this, m_process.copyRef(), *mainFrameID, shouldDelayClosingUntilFirstLayerFlush);
907
908 LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %s" PRIu64, identifier().toUInt64(), suspendedPage->loggingString(), m_process->processIdentifier(), fromItem ? fromItem->itemID().logString() : 0);
909
910 m_lastSuspendedPage = makeWeakPtr(*suspendedPage);
911
912 if (fromItem && shouldUseBackForwardCache())
913 backForwardCache().addEntry(*fromItem, WTFMove(suspendedPage));
914 else {
915 ASSERT(needsSuspendedPageToPreventFlashing);
916 m_suspendedPageKeptToPreventFlashing = WTFMove(suspendedPage);
917 }
918
919 return true;
920}
921
922WebBackForwardCache& WebPageProxy::backForwardCache() const
923{
924 return process().processPool().backForwardCache();
925}
926
927bool WebPageProxy::shouldUseBackForwardCache() const
928{
929 return m_preferences->usesBackForwardCache() && backForwardCache().capacity() > 0;
930}
931
932void WebPageProxy::swapToProvisionalPage(std::unique_ptr<ProvisionalPageProxy> provisionalPage)
933{
934 ASSERT(!m_isClosed);
935 WEBPAGEPROXY_RELEASE_LOG(Loading, "swapToProvisionalPage: newWebPageID=%" PRIu64, provisionalPage->webPageID().toUInt64());
936
937 m_process = provisionalPage->process();
938 m_webPageID = provisionalPage->webPageID();
939 pageClient().didChangeWebPageID();
940 m_websiteDataStore = m_process->websiteDataStore();
941
942#if HAVE(VISIBILITY_PROPAGATION_VIEW)
943 m_contextIDForVisibilityPropagationInWebProcess = provisionalPage->contextIDForVisibilityPropagationInWebProcess();
944#if ENABLE(GPU_PROCESS)
945 m_contextIDForVisibilityPropagationInGPUProcess = provisionalPage->contextIDForVisibilityPropagationInGPUProcess();
946#endif
947#endif
948
949 // FIXME: Do we really need to disable this logging in ephemeral sessions?
950 if (m_logger)
951 m_logger->setEnabled(this, !sessionID().isEphemeral());
952
953 m_hasRunningProcess = true;
954
955 ASSERT(!m_drawingArea);
956 setDrawingArea(provisionalPage->takeDrawingArea());
957 ASSERT(!m_mainFrame);
958 m_mainFrame = provisionalPage->mainFrame();
959
960 m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::No);
961 m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID, *this);
962
963 finishAttachingToWebProcess(ProcessLaunchReason::ProcessSwap);
964
965#if PLATFORM(COCOA)
966 auto accessibilityToken = provisionalPage->takeAccessibilityToken();
967 if (!accessibilityToken.isEmpty())
968 registerWebProcessAccessibilityToken({ accessibilityToken.data(), accessibilityToken.size() });
969#endif
970}
971
972void WebPageProxy::finishAttachingToWebProcess(ProcessLaunchReason reason)
973{
974 ASSERT(m_process->state() != AuxiliaryProcessProxy::State::Terminated);
975
976 updateActivityState();
977 updateThrottleState();
978
979 didAttachToRunningProcess();
980
981 // In the process-swap case, the ProvisionalPageProxy already took care of initializing the WebPage in the WebProcess.
982 if (reason != ProcessLaunchReason::ProcessSwap)
983 initializeWebPage();
984
985 m_inspector->updateForNewPageProcess(*this);
986
987#if ENABLE(REMOTE_INSPECTOR)
988 remoteInspectorInformationDidChange();
989#endif
990
991 updateWheelEventActivityAfterProcessSwap();
992
993 pageClient().didRelaunchProcess();
994 m_pageLoadState.didSwapWebProcesses();
995 if (reason != ProcessLaunchReason::InitialProcess)
996 m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
997}
998
999void WebPageProxy::didAttachToRunningProcess()
1000{
1001 ASSERT(hasRunningProcess());
1002
1003#if ENABLE(FULLSCREEN_API)
1004 ASSERT(!m_fullScreenManager);
1005 m_fullScreenManager = makeUnique<WebFullScreenManagerProxy>(*this, pageClient().fullScreenManagerProxyClient());
1006#endif
1007#if ENABLE(VIDEO_PRESENTATION_MODE)
1008 ASSERT(!m_playbackSessionManager);
1009 m_playbackSessionManager = PlaybackSessionManagerProxy::create(*this);
1010 ASSERT(!m_videoFullscreenManager);
1011 m_videoFullscreenManager = VideoFullscreenManagerProxy::create(*this, *m_playbackSessionManager);
1012 if (m_videoFullscreenManager)
1013 m_videoFullscreenManager->setMockVideoPresentationModeEnabled(m_mockVideoPresentationModeEnabled);
1014#endif
1015
1016#if ENABLE(APPLE_PAY)
1017 ASSERT(!m_paymentCoordinator);
1018 m_paymentCoordinator = makeUnique<WebPaymentCoordinatorProxy>(*this);
1019#endif
1020
1021#if USE(SYSTEM_PREVIEW)
1022 ASSERT(!m_systemPreviewController);
1023 m_systemPreviewController = makeUnique<SystemPreviewController>(*this);
1024#endif
1025
1026#if HAVE(ARKIT_INLINE_PREVIEW)
1027 if (m_preferences->modelElementEnabled()) {
1028 ASSERT(!m_modelElementController);
1029 m_modelElementController = makeUnique<ModelElementController>(*this);
1030 }
1031#endif
1032
1033#if ENABLE(WEB_AUTHN)
1034 ASSERT(!m_credentialsMessenger);
1035 m_credentialsMessenger = makeUnique<WebAuthenticatorCoordinatorProxy>(*this);
1036#endif
1037
1038#if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
1039 ASSERT(!m_webDeviceOrientationUpdateProviderProxy);
1040 m_webDeviceOrientationUpdateProviderProxy = makeUnique<WebDeviceOrientationUpdateProviderProxy>(*this);
1041#endif
1042
1043#if ENABLE(WEBXR) && PLATFORM(COCOA)
1044 ASSERT(!m_xrSystem);
1045 m_xrSystem = makeUnique<PlatformXRSystem>(*this);
1046#endif
1047}
1048
1049RefPtr<API::Navigation> WebPageProxy::launchProcessForReload()
1050{
1051 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcessForReload:");
1052
1053 if (m_isClosed) {
1054 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcessForReload: page is closed");
1055 return nullptr;
1056 }
1057
1058 ASSERT(!hasRunningProcess());
1059 auto registrableDomain = m_backForwardList->currentItem() ? RegistrableDomain { URL(URL(), m_backForwardList->currentItem()->url()) } : RegistrableDomain { };
1060 launchProcess(registrableDomain, ProcessLaunchReason::Crash);
1061
1062 if (!m_backForwardList->currentItem()) {
1063 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcessForReload: no current item to reload");
1064 return nullptr;
1065 }
1066
1067 auto navigation = m_navigationState->createReloadNavigation(m_backForwardList->currentItem());
1068
1069 String url = currentURL();
1070 if (!url.isEmpty()) {
1071 auto transaction = m_pageLoadState.transaction();
1072 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
1073 }
1074
1075 // We allow stale content when reloading a WebProcess that's been killed or crashed.
1076 send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), m_backForwardList->currentItem()->itemID(), FrameLoadType::IndexedBackForward, ShouldTreatAsContinuingLoad::No, std::nullopt));
1077 m_process->startResponsivenessTimer();
1078
1079 return navigation;
1080}
1081
1082void WebPageProxy::setDrawingArea(std::unique_ptr<DrawingAreaProxy>&& drawingArea)
1083{
1084 m_drawingArea = WTFMove(drawingArea);
1085 if (!m_drawingArea)
1086 return;
1087
1088 m_drawingArea->startReceivingMessages();
1089 m_drawingArea->setSize(viewSize());
1090
1091#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
1092 if (m_drawingArea->type() == DrawingAreaTypeRemoteLayerTree) {
1093 m_scrollingCoordinatorProxy = makeUnique<RemoteScrollingCoordinatorProxy>(*this);
1094#if PLATFORM(IOS_FAMILY)
1095 // On iOS, main frame scrolls are sent in terms of visible rect updates.
1096 m_scrollingCoordinatorProxy->setPropagatesMainFrameScrolls(false);
1097#endif
1098 }
1099#endif
1100}
1101
1102void WebPageProxy::initializeWebPage()
1103{
1104 if (!hasRunningProcess())
1105 return;
1106
1107 setDrawingArea(pageClient().createDrawingAreaProxy(m_process));
1108 ASSERT(m_drawingArea);
1109
1110#if ENABLE(REMOTE_INSPECTOR)
1111 // Initialize remote inspector connection now that we have a sub-process that is hosting one of our web views.
1112 Inspector::RemoteInspector::singleton();
1113#endif
1114
1115 if (auto& attributedBundleIdentifier = m_configuration->attributedBundleIdentifier(); !!attributedBundleIdentifier) {
1116 WebPageNetworkParameters parameters { attributedBundleIdentifier };
1117 websiteDataStore().networkProcess().send(Messages::NetworkProcess::AddWebPageNetworkParameters(sessionID(), m_identifier, WTFMove(parameters)), 0);
1118 }
1119
1120 send(Messages::WebProcess::CreateWebPage(m_webPageID, creationParameters(m_process, *m_drawingArea)), 0);
1121
1122 m_process->addVisitedLinkStoreUser(visitedLinkStore(), m_identifier);
1123}
1124
1125void WebPageProxy::close()
1126{
1127 if (m_isClosed)
1128 return;
1129
1130 WEBPAGEPROXY_RELEASE_LOG(Loading, "close:");
1131
1132 m_isClosed = true;
1133
1134 reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
1135
1136 if (m_activePopupMenu)
1137 m_activePopupMenu->cancelTracking();
1138
1139 if (m_controlledByAutomation) {
1140 if (auto* automationSession = process().processPool().automationSession())
1141 automationSession->willClosePage(*this);
1142 }
1143
1144#if ENABLE(CONTEXT_MENUS)
1145 m_activeContextMenu = nullptr;
1146#endif
1147
1148 m_provisionalPage = nullptr;
1149
1150 m_inspector->invalidate();
1151
1152 m_backForwardList->pageClosed();
1153 m_inspectorController->pageClosed();
1154#if ENABLE(REMOTE_INSPECTOR)
1155 m_inspectorDebuggable = nullptr;
1156#endif
1157 pageClient().pageClosed();
1158
1159 m_process->disconnectFramesFromPage(this);
1160
1161 resetState(ResetStateReason::PageInvalidated);
1162
1163 m_loaderClient = nullptr;
1164 m_navigationClient = makeUniqueRef<API::NavigationClient>();
1165 m_policyClient = nullptr;
1166 m_iconLoadingClient = makeUnique<API::IconLoadingClient>();
1167 m_formClient = makeUnique<API::FormClient>();
1168 m_uiClient = makeUnique<API::UIClient>();
1169 m_findClient = makeUnique<API::FindClient>();
1170 m_findMatchesClient = makeUnique<API::FindMatchesClient>();
1171 m_diagnosticLoggingClient = nullptr;
1172#if ENABLE(CONTEXT_MENUS)
1173 m_contextMenuClient = makeUnique<API::ContextMenuClient>();
1174#endif
1175#if ENABLE(FULLSCREEN_API)
1176 m_fullscreenClient = makeUnique<API::FullscreenClient>();
1177#endif
1178
1179 m_process->processPool().backForwardCache().removeEntriesForPage(*this);
1180
1181 RunLoop::current().dispatch([destinationID = messageSenderDestinationID(), protectedProcess = m_process.copyRef(), preventProcessShutdownScope = m_process->shutdownPreventingScope()] {
1182 protectedProcess->send(Messages::WebPage::Close(), destinationID);
1183 });
1184 m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
1185 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
1186 m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this);
1187
1188 // Null out related WebPageProxy to avoid leaks.
1189 m_configuration->setRelatedPage(nullptr);
1190
1191#if PLATFORM(IOS_FAMILY)
1192 // Make sure we don't hold a process assertion after getting closed.
1193 m_isVisibleActivity = nullptr;
1194 m_isAudibleActivity = nullptr;
1195 m_isCapturingActivity = nullptr;
1196 m_openingAppLinkActivity = nullptr;
1197 m_audibleActivityTimer.stop();
1198#endif
1199
1200 stopAllURLSchemeTasks();
1201 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
1202}
1203
1204bool WebPageProxy::tryClose()
1205{
1206 if (!hasRunningProcess())
1207 return true;
1208
1209 WEBPAGEPROXY_RELEASE_LOG(Process, "tryClose:");
1210
1211 // Close without delay if the process allows it. Our goal is to terminate
1212 // the process, so we check a per-process status bit.
1213 if (m_process->isSuddenTerminationEnabled())
1214 return true;
1215
1216 m_tryCloseTimeoutTimer.startOneShot(tryCloseTimeoutDelay);
1217 sendWithAsyncReply(Messages::WebPage::TryClose(), [this, weakThis = makeWeakPtr(*this)](bool shouldClose) {
1218 if (!weakThis)
1219 return;
1220
1221 // If we timed out, don't ask the client to close again.
1222 if (!m_tryCloseTimeoutTimer.isActive())
1223 return;
1224
1225 m_tryCloseTimeoutTimer.stop();
1226 if (shouldClose)
1227 closePage();
1228 });
1229 return false;
1230}
1231
1232void WebPageProxy::tryCloseTimedOut()
1233{
1234 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "tryCloseTimedOut: Timed out waiting for the process to respond to the WebPage::TryClose IPC, closing the page now");
1235 closePage();
1236}
1237
1238void WebPageProxy::maybeInitializeSandboxExtensionHandle(WebProcessProxy& process, const URL& url, const URL& resourceDirectoryURL, SandboxExtension::Handle& sandboxExtensionHandle, bool checkAssumedReadAccessToResourceURL)
1239{
1240 if (!url.isLocalFile())
1241 return;
1242
1243#if HAVE(AUDIT_TOKEN)
1244 // If the process is still launching then it does not have a PID yet. We will take care of creating the sandbox extension
1245 // once the process has finished launching.
1246 if (process.isLaunching() || process.wasTerminated())
1247 return;
1248#endif
1249
1250 if (!resourceDirectoryURL.isEmpty()) {
1251 if (checkAssumedReadAccessToResourceURL && process.hasAssumedReadAccessToURL(resourceDirectoryURL))
1252 return;
1253
1254 bool createdExtension = false;
1255#if HAVE(AUDIT_TOKEN)
1256 ASSERT(process.connection() && process.connection()->getAuditToken());
1257 if (process.connection() && process.connection()->getAuditToken())
1258 createdExtension = SandboxExtension::createHandleForReadByAuditToken(resourceDirectoryURL.fileSystemPath(), *(process.connection()->getAuditToken()), sandboxExtensionHandle);
1259 else
1260#endif
1261 createdExtension = SandboxExtension::createHandle(resourceDirectoryURL.fileSystemPath(), SandboxExtension::Type::ReadOnly, sandboxExtensionHandle);
1262
1263 if (createdExtension) {
1264 process.assumeReadAccessToBaseURL(*this, resourceDirectoryURL.string());
1265 return;
1266 }
1267 }
1268
1269 if (process.hasAssumedReadAccessToURL(url))
1270 return;
1271
1272 // Inspector resources are in a directory with assumed access.
1273 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!WebKit::isInspectorPage(*this));
1274
1275 bool createdExtension = false;
1276#if HAVE(AUDIT_TOKEN)
1277 ASSERT(process.connection() && process.connection()->getAuditToken());
1278 if (process.connection() && process.connection()->getAuditToken())
1279 createdExtension = SandboxExtension::createHandleForReadByAuditToken("/", *(process.connection()->getAuditToken()), sandboxExtensionHandle);
1280 else
1281#endif
1282 createdExtension = SandboxExtension::createHandle("/", SandboxExtension::Type::ReadOnly, sandboxExtensionHandle);
1283
1284 if (createdExtension) {
1285 willAcquireUniversalFileReadSandboxExtension(process);
1286 return;
1287 }
1288
1289#if PLATFORM(COCOA)
1290 if (!linkedOnOrAfter(WebCore::SDKVersion::FirstWithoutUnconditionalUniversalSandboxExtension))
1291 willAcquireUniversalFileReadSandboxExtension(process);
1292#endif
1293
1294 // We failed to issue an universal file read access sandbox, fall back to issuing one for the base URL instead.
1295 auto baseURL = url.truncatedForUseAsBase();
1296 auto basePath = baseURL.fileSystemPath();
1297 if (basePath.isNull())
1298 return;
1299#if HAVE(AUDIT_TOKEN)
1300 if (process.connection() && process.connection()->getAuditToken())
1301 createdExtension = SandboxExtension::createHandleForReadByAuditToken(basePath, *(process.connection()->getAuditToken()), sandboxExtensionHandle);
1302 else
1303#endif
1304 createdExtension = SandboxExtension::createHandle(basePath, SandboxExtension::Type::ReadOnly, sandboxExtensionHandle);
1305
1306 if (createdExtension)
1307 process.assumeReadAccessToBaseURL(*this, baseURL.string());
1308}
1309
1310#if !PLATFORM(COCOA)
1311
1312void WebPageProxy::addPlatformLoadParameters(WebProcessProxy&, LoadParameters&)
1313{
1314}
1315
1316#endif
1317
1318WebProcessProxy& WebPageProxy::ensureRunningProcess()
1319{
1320 if (!hasRunningProcess())
1321 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1322
1323 return m_process;
1324}
1325
1326RefPtr<API::Navigation> WebPageProxy::loadRequest(ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData)
1327{
1328 if (m_isClosed)
1329 return nullptr;
1330
1331 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadRequest:");
1332
1333 if (!hasRunningProcess())
1334 launchProcess(RegistrableDomain { request.url() }, ProcessLaunchReason::InitialProcess);
1335
1336 auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
1337
1338 if (shouldForceForegroundPriorityForClientNavigation())
1339 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1340
1341#if PLATFORM(COCOA)
1342 setLastNavigationWasAppBound(request);
1343#endif
1344
1345 loadRequestWithNavigationShared(m_process.copyRef(), m_webPageID, navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain());
1346 return navigation;
1347}
1348
1349void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, std::optional<WebsitePoliciesData>&& websitePolicies)
1350{
1351 ASSERT(!m_isClosed);
1352
1353 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadRequestWithNavigationShared:");
1354
1355 auto transaction = m_pageLoadState.transaction();
1356
1357 auto url = request.url();
1358 if (shouldTreatAsContinuingLoad != ShouldTreatAsContinuingLoad::Yes)
1359 m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), url.string() });
1360
1361 LoadParameters loadParameters;
1362 loadParameters.navigationID = navigation.navigationID();
1363 loadParameters.request = WTFMove(request);
1364 loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1365 loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1366 loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1367 loadParameters.websitePolicies = WTFMove(websitePolicies);
1368 loadParameters.lockHistory = navigation.lockHistory();
1369 loadParameters.lockBackForwardList = navigation.lockBackForwardList();
1370 loadParameters.clientRedirectSourceForHistory = navigation.clientRedirectSourceForHistory();
1371 loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
1372 maybeInitializeSandboxExtensionHandle(process, url, m_pageLoadState.resourceDirectoryURL(), loadParameters.sandboxExtensionHandle);
1373
1374 addPlatformLoadParameters(process, loadParameters);
1375
1376 preconnectTo(url);
1377
1378 navigation.setIsLoadedWithNavigationShared(true);
1379
1380 if (!process->isLaunching() || !url.isLocalFile())
1381 process->send(Messages::WebPage::LoadRequest(loadParameters), webPageID);
1382 else
1383 process->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(loadParameters, m_pageLoadState.resourceDirectoryURL(), m_identifier, true), webPageID);
1384 process->startResponsivenessTimer();
1385}
1386
1387RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData)
1388{
1389 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile:");
1390
1391 if (m_isClosed) {
1392 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile: page is closed");
1393 return nullptr;
1394 }
1395
1396 if (!hasRunningProcess())
1397 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1398
1399 URL fileURL = URL(URL(), fileURLString);
1400 if (!fileURL.isLocalFile()) {
1401 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile: file is not local");
1402 return nullptr;
1403 }
1404
1405 URL resourceDirectoryURL;
1406 if (resourceDirectoryURLString.isNull())
1407 resourceDirectoryURL = URL({ }, "file:///"_s);
1408 else {
1409 resourceDirectoryURL = URL(URL(), resourceDirectoryURLString);
1410 if (!resourceDirectoryURL.isLocalFile()) {
1411 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile: resource URL is not local");
1412 return nullptr;
1413 }
1414 }
1415
1416 auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(fileURL), m_backForwardList->currentItem());
1417
1418 if (shouldForceForegroundPriorityForClientNavigation())
1419 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1420
1421 auto transaction = m_pageLoadState.transaction();
1422
1423 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), fileURLString }, resourceDirectoryURL);
1424
1425 LoadParameters loadParameters;
1426 loadParameters.navigationID = navigation->navigationID();
1427 loadParameters.request = fileURL;
1428 loadParameters.shouldOpenExternalURLsPolicy = ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1429 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1430 const bool checkAssumedReadAccessToResourceURL = false;
1431 maybeInitializeSandboxExtensionHandle(m_process, fileURL, resourceDirectoryURL, loadParameters.sandboxExtensionHandle, checkAssumedReadAccessToResourceURL);
1432 addPlatformLoadParameters(m_process, loadParameters);
1433
1434 if (m_process->isLaunching())
1435 send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(loadParameters, resourceDirectoryURL, m_identifier, checkAssumedReadAccessToResourceURL));
1436 else
1437 send(Messages::WebPage::LoadRequest(loadParameters));
1438 m_process->startResponsivenessTimer();
1439
1440 return navigation;
1441}
1442
1443RefPtr<API::Navigation> WebPageProxy::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1444{
1445 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadData:");
1446
1447#if ENABLE(APP_BOUND_DOMAINS)
1448 if (MIMEType == "text/html"_s && !isFullWebBrowser())
1449 m_limitsNavigationsToAppBoundDomains = true;
1450#endif
1451
1452 if (m_isClosed) {
1453 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadData: page is closed");
1454 return nullptr;
1455 }
1456
1457 if (!hasRunningProcess())
1458 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1459
1460 auto navigation = m_navigationState->createLoadDataNavigation(makeUnique<API::SubstituteData>(data.vector(), MIMEType, encoding, baseURL, userData));
1461
1462 if (shouldForceForegroundPriorityForClientNavigation())
1463 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1464
1465 loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain(), std::nullopt, shouldOpenExternalURLsPolicy);
1466 return navigation;
1467}
1468
1469void WebPageProxy::loadDataWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, std::optional<WebsitePoliciesData>&& websitePolicies, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1470{
1471 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadDataWithNavigation");
1472
1473 ASSERT(!m_isClosed);
1474
1475 auto transaction = m_pageLoadState.transaction();
1476
1477 m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), !baseURL.isEmpty() ? baseURL : aboutBlankURL().string() });
1478
1479 LoadParameters loadParameters;
1480 loadParameters.navigationID = navigation.navigationID();
1481 loadParameters.data = data;
1482 loadParameters.MIMEType = MIMEType;
1483 loadParameters.encodingName = encoding;
1484 loadParameters.baseURLString = baseURL;
1485 loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1486 loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1487 loadParameters.websitePolicies = WTFMove(websitePolicies);
1488 loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1489 loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
1490 addPlatformLoadParameters(process, loadParameters);
1491
1492 process->assumeReadAccessToBaseURL(*this, baseURL);
1493 process->send(Messages::WebPage::LoadData(loadParameters), webPageID);
1494 process->startResponsivenessTimer();
1495}
1496
1497RefPtr<API::Navigation> WebPageProxy::loadSimulatedRequest(WebCore::ResourceRequest&& simulatedRequest, WebCore::ResourceResponse&& simulatedResponse, const IPC::DataReference& data)
1498{
1499 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadSimulatedRequest:");
1500
1501#if PLATFORM(COCOA)
1502 setLastNavigationWasAppBound(simulatedRequest);
1503#endif
1504
1505#if ENABLE(APP_BOUND_DOMAINS)
1506 if (simulatedResponse.mimeType() == "text/html"_s && !isFullWebBrowser())
1507 m_limitsNavigationsToAppBoundDomains = true;
1508#endif
1509
1510 if (m_isClosed) {
1511 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadSimulatedRequest: page is closed");
1512 return nullptr;
1513 }
1514
1515 if (!hasRunningProcess())
1516 launchProcess(RegistrableDomain { simulatedRequest.url() }, ProcessLaunchReason::InitialProcess);
1517
1518 auto navigation = m_navigationState->createSimulatedLoadWithDataNavigation(ResourceRequest(simulatedRequest), makeUnique<API::SubstituteData>(data.vector(), ResourceResponse(simulatedResponse), nullptr), m_backForwardList->currentItem());
1519
1520 if (shouldForceForegroundPriorityForClientNavigation())
1521 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1522
1523 auto transaction = m_pageLoadState.transaction();
1524
1525 auto baseURL = simulatedRequest.url().string();
1526 simulatedResponse.setURL(simulatedRequest.url()); // These should always match for simulated load
1527
1528 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), !baseURL.isEmpty() ? baseURL : aboutBlankURL().string() });
1529
1530 LoadParameters loadParameters;
1531 loadParameters.navigationID = navigation->navigationID();
1532 loadParameters.request = WTFMove(simulatedRequest);
1533 loadParameters.data = data;
1534 loadParameters.MIMEType = simulatedResponse.mimeType();
1535 loadParameters.encodingName = simulatedResponse.textEncodingName();
1536 loadParameters.baseURLString = baseURL;
1537 loadParameters.shouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1538 loadParameters.shouldTreatAsContinuingLoad = false;
1539 loadParameters.lockHistory = navigation->lockHistory();
1540 loadParameters.lockBackForwardList = navigation->lockBackForwardList();
1541 loadParameters.clientRedirectSourceForHistory = navigation->clientRedirectSourceForHistory();
1542 loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain();
1543
1544 simulatedResponse.setExpectedContentLength(data.size());
1545 simulatedResponse.includeCertificateInfo();
1546
1547 addPlatformLoadParameters(m_process, loadParameters);
1548
1549 m_process->assumeReadAccessToBaseURL(*this, baseURL);
1550 m_process->send(Messages::WebPage::LoadSimulatedRequestAndResponse(loadParameters, simulatedResponse), m_webPageID);
1551 m_process->startResponsivenessTimer();
1552 return navigation;
1553}
1554
1555void WebPageProxy::loadAlternateHTML(const IPC::DataReference& htmlData, const String& encoding, const URL& baseURL, const URL& unreachableURL, API::Object* userData)
1556{
1557 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadAlternateHTML");
1558
1559 // When the UIProcess is in the process of handling a failing provisional load, do not attempt to
1560 // start a second alternative HTML load as this will prevent the page load state from being
1561 // handled properly.
1562 if (m_isClosed || m_isLoadingAlternateHTMLStringForFailingProvisionalLoad) {
1563 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadAlternateHTML: page is closed (or other)");
1564 return;
1565 }
1566
1567 if (!m_failingProvisionalLoadURL.isEmpty())
1568 m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = true;
1569
1570 if (!hasRunningProcess())
1571 launchProcess(RegistrableDomain { baseURL }, ProcessLaunchReason::InitialProcess);
1572
1573 auto transaction = m_pageLoadState.transaction();
1574
1575 m_pageLoadState.setPendingAPIRequest(transaction, { 0, unreachableURL.string() });
1576 m_pageLoadState.setUnreachableURL(transaction, unreachableURL.string());
1577
1578 if (m_mainFrame)
1579 m_mainFrame->setUnreachableURL(unreachableURL);
1580
1581 LoadParameters loadParameters;
1582 loadParameters.navigationID = 0;
1583 loadParameters.data = htmlData;
1584 loadParameters.MIMEType = "text/html"_s;
1585 loadParameters.encodingName = encoding;
1586 loadParameters.baseURLString = baseURL.string();
1587 loadParameters.unreachableURLString = unreachableURL.string();
1588 loadParameters.provisionalLoadErrorURLString = m_failingProvisionalLoadURL;
1589 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1590 addPlatformLoadParameters(process(), loadParameters);
1591
1592 m_process->assumeReadAccessToBaseURL(*this, baseURL.string());
1593 m_process->assumeReadAccessToBaseURL(*this, unreachableURL.string());
1594 send(Messages::WebPage::LoadAlternateHTML(loadParameters));
1595 m_process->startResponsivenessTimer();
1596}
1597
1598void WebPageProxy::loadWebArchiveData(API::Data* webArchiveData, API::Object* userData)
1599{
1600 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadWebArchiveData:");
1601
1602 if (m_isClosed) {
1603 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadWebArchiveData: page is closed");
1604 return;
1605 }
1606
1607 if (!hasRunningProcess())
1608 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1609
1610 auto transaction = m_pageLoadState.transaction();
1611 m_pageLoadState.setPendingAPIRequest(transaction, { 0, aboutBlankURL().string() });
1612
1613 LoadParameters loadParameters;
1614 loadParameters.navigationID = 0;
1615 loadParameters.data = webArchiveData->dataReference();
1616 loadParameters.MIMEType = "application/x-webarchive"_s;
1617 loadParameters.encodingName = "utf-16"_s;
1618 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1619 addPlatformLoadParameters(process(), loadParameters);
1620
1621 send(Messages::WebPage::LoadData(loadParameters));
1622 m_process->startResponsivenessTimer();
1623}
1624
1625void WebPageProxy::navigateToPDFLinkWithSimulatedClick(const String& urlString, IntPoint documentPoint, IntPoint screenPoint)
1626{
1627 WEBPAGEPROXY_RELEASE_LOG(Loading, "navigateToPDFLinkWithSimulatedClick:");
1628
1629 if (m_isClosed) {
1630 WEBPAGEPROXY_RELEASE_LOG(Loading, "navigateToPDFLinkWithSimulatedClick: page is closed:");
1631 return;
1632 }
1633
1634 if (WTF::protocolIsJavaScript(urlString))
1635 return;
1636
1637 if (!hasRunningProcess())
1638 launchProcess(RegistrableDomain { URL(URL(), urlString) }, ProcessLaunchReason::InitialProcess);
1639
1640 send(Messages::WebPage::NavigateToPDFLinkWithSimulatedClick(urlString, documentPoint, screenPoint));
1641 m_process->startResponsivenessTimer();
1642}
1643
1644void WebPageProxy::stopLoading()
1645{
1646 WEBPAGEPROXY_RELEASE_LOG(Loading, "stopLoading:");
1647
1648 if (!hasRunningProcess()) {
1649 WEBPAGEPROXY_RELEASE_LOG(Loading, "navigateToPDFLinkWithSimulatedClick: page is not valid");
1650 return;
1651 }
1652
1653 send(Messages::WebPage::StopLoading());
1654 if (m_provisionalPage) {
1655 m_provisionalPage->cancel();
1656 m_provisionalPage = nullptr;
1657 }
1658 m_process->startResponsivenessTimer();
1659}
1660
1661RefPtr<API::Navigation> WebPageProxy::reload(OptionSet<WebCore::ReloadOption> options)
1662{
1663 WEBPAGEPROXY_RELEASE_LOG(Loading, "reload:");
1664
1665 // Make sure the Network & GPU processes are still responsive. This is so that reload() gets us out of the bad state if one of these
1666 // processes is hung.
1667 websiteDataStore().networkProcess().checkForResponsiveness();
1668#if ENABLE(GPU_PROCESS)
1669 if (auto* gpuProcess = process().processPool().gpuProcess())
1670 gpuProcess->checkForResponsiveness();
1671#endif
1672
1673 SandboxExtension::Handle sandboxExtensionHandle;
1674
1675 String url = currentURL();
1676 if (!url.isEmpty()) {
1677 // We may not have an extension yet if back/forward list was reinstated after a WebProcess crash or a browser relaunch
1678 maybeInitializeSandboxExtensionHandle(m_process, URL(URL(), url), currentResourceDirectoryURL(), sandboxExtensionHandle);
1679 }
1680
1681 if (!hasRunningProcess())
1682 return launchProcessForReload();
1683
1684 auto navigation = m_navigationState->createReloadNavigation(m_backForwardList->currentItem());
1685
1686 if (!url.isEmpty()) {
1687 auto transaction = m_pageLoadState.transaction();
1688 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
1689 }
1690
1691 // Store decision to reload without content blockers on the navigation so that we can later set the corresponding
1692 // WebsitePolicies flag in WebPageProxy::receivedNavigationPolicyDecision().
1693 if (options.contains(WebCore::ReloadOption::DisableContentBlockers))
1694 navigation->setUserContentExtensionsEnabled(false);
1695
1696 send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle));
1697 m_process->startResponsivenessTimer();
1698
1699#if ENABLE(SPEECH_SYNTHESIS)
1700 resetSpeechSynthesizer();
1701#endif
1702
1703 return navigation;
1704}
1705
1706void WebPageProxy::recordAutomaticNavigationSnapshot()
1707{
1708 if (m_shouldSuppressNextAutomaticNavigationSnapshot)
1709 return;
1710
1711 if (WebBackForwardListItem* item = m_backForwardList->currentItem())
1712 recordNavigationSnapshot(*item);
1713}
1714
1715void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item)
1716{
1717 if (!m_shouldRecordNavigationSnapshots)
1718 return;
1719
1720#if PLATFORM(COCOA) || PLATFORM(GTK)
1721 ViewSnapshotStore::singleton().recordSnapshot(*this, item);
1722#else
1723 UNUSED_PARAM(item);
1724#endif
1725}
1726
1727RefPtr<API::Navigation> WebPageProxy::goForward()
1728{
1729 WebBackForwardListItem* forwardItem = m_backForwardList->forwardItem();
1730 if (!forwardItem)
1731 return nullptr;
1732
1733 return goToBackForwardItem(*forwardItem, FrameLoadType::Forward);
1734}
1735
1736RefPtr<API::Navigation> WebPageProxy::goBack()
1737{
1738 WebBackForwardListItem* backItem = m_backForwardList->backItem();
1739 if (!backItem)
1740 return nullptr;
1741
1742 return goToBackForwardItem(*backItem, FrameLoadType::Back);
1743}
1744
1745RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item)
1746{
1747 return goToBackForwardItem(item, FrameLoadType::IndexedBackForward);
1748}
1749
1750RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item, FrameLoadType frameLoadType)
1751{
1752 WEBPAGEPROXY_RELEASE_LOG(Loading, "goToBackForwardItem:");
1753 LOG(Loading, "WebPageProxy %p goToBackForwardItem to item URL %s", this, item.url().utf8().data());
1754
1755 if (m_isClosed) {
1756 WEBPAGEPROXY_RELEASE_LOG(Loading, "goToBackForwardItem: page is closed");
1757 return nullptr;
1758 }
1759
1760 if (!hasRunningProcess()) {
1761 launchProcess(RegistrableDomain { URL(URL(), item.url()) }, ProcessLaunchReason::InitialProcess);
1762
1763 if (&item != m_backForwardList->currentItem())
1764 m_backForwardList->goToItem(item);
1765 }
1766
1767 RefPtr<API::Navigation> navigation;
1768 if (!m_backForwardList->currentItem()->itemIsInSameDocument(item))
1769 navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), frameLoadType);
1770
1771 auto transaction = m_pageLoadState.transaction();
1772 m_pageLoadState.setPendingAPIRequest(transaction, { navigation ? navigation->navigationID() : 0, item.url() });
1773
1774 send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item.itemID(), frameLoadType, ShouldTreatAsContinuingLoad::No, std::nullopt));
1775 m_process->startResponsivenessTimer();
1776
1777 return navigation;
1778}
1779
1780void WebPageProxy::tryRestoreScrollPosition()
1781{
1782 WEBPAGEPROXY_RELEASE_LOG(Loading, "tryRestoreScrollPosition:");
1783
1784 if (!hasRunningProcess()) {
1785 WEBPAGEPROXY_RELEASE_LOG(Loading, "tryRestoreScrollPosition: page is not valid");
1786 return;
1787 }
1788
1789 send(Messages::WebPage::TryRestoreScrollPosition());
1790}
1791
1792void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<Ref<WebBackForwardListItem>>&& removed)
1793{
1794 PageClientProtector protector(pageClient());
1795
1796 if (!m_navigationClient->didChangeBackForwardList(*this, added, removed) && m_loaderClient)
1797 m_loaderClient->didChangeBackForwardList(*this, added, WTFMove(removed));
1798
1799 auto transaction = m_pageLoadState.transaction();
1800
1801 m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
1802 m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
1803}
1804
1805void WebPageProxy::willGoToBackForwardListItem(const BackForwardItemIdentifier& itemID, bool inBackForwardCache)
1806{
1807 PageClientProtector protector(pageClient());
1808
1809 if (auto* item = m_backForwardList->itemForID(itemID))
1810 m_navigationClient->willGoToBackForwardListItem(*this, *item, inBackForwardCache);
1811}
1812
1813bool WebPageProxy::shouldKeepCurrentBackForwardListItemInList(WebBackForwardListItem& item)
1814{
1815 PageClientProtector protector(pageClient());
1816
1817 return !m_loaderClient || m_loaderClient->shouldKeepCurrentBackForwardListItemInList(*this, item);
1818}
1819
1820bool WebPageProxy::canShowMIMEType(const String& mimeType)
1821{
1822 if (MIMETypeRegistry::canShowMIMEType(mimeType))
1823 return true;
1824
1825#if ENABLE(NETSCAPE_PLUGIN_API)
1826 String newMimeType = mimeType;
1827 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL());
1828 if (!plugin.path.isNull() && m_preferences->pluginsEnabled())
1829 return true;
1830#endif // ENABLE(NETSCAPE_PLUGIN_API)
1831
1832#if PLATFORM(COCOA)
1833 // On Mac, we can show PDFs.
1834 if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebProcessPool::omitPDFSupport())
1835 return true;
1836#endif // PLATFORM(COCOA)
1837
1838 return false;
1839}
1840
1841void WebPageProxy::setControlledByAutomation(bool controlled)
1842{
1843 if (m_controlledByAutomation == controlled)
1844 return;
1845
1846 m_controlledByAutomation = controlled;
1847
1848 if (!hasRunningProcess())
1849 return;
1850
1851 send(Messages::WebPage::SetControlledByAutomation(controlled));
1852 websiteDataStore().networkProcess().send(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation), 0);
1853}
1854
1855void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
1856{
1857 MESSAGE_CHECK(m_process, !targetId.isEmpty());
1858 m_inspectorController->createInspectorTarget(targetId, type);
1859}
1860
1861void WebPageProxy::destroyInspectorTarget(const String& targetId)
1862{
1863 MESSAGE_CHECK(m_process, !targetId.isEmpty());
1864 m_inspectorController->destroyInspectorTarget(targetId);
1865}
1866
1867void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message)
1868{
1869 m_inspectorController->sendMessageToInspectorFrontend(targetId, message);
1870}
1871
1872#if ENABLE(REMOTE_INSPECTOR)
1873void WebPageProxy::setIndicating(bool indicating)
1874{
1875 if (!hasRunningProcess())
1876 return;
1877
1878 send(Messages::WebPage::SetIndicating(indicating));
1879}
1880
1881bool WebPageProxy::allowsRemoteInspection() const
1882{
1883 return m_inspectorDebuggable->remoteDebuggingAllowed();
1884}
1885
1886void WebPageProxy::setAllowsRemoteInspection(bool allow)
1887{
1888 m_inspectorDebuggable->setRemoteDebuggingAllowed(allow);
1889}
1890
1891String WebPageProxy::remoteInspectionNameOverride() const
1892{
1893 return m_inspectorDebuggable->nameOverride();
1894}
1895
1896void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
1897{
1898 m_inspectorDebuggable->setNameOverride(name);
1899}
1900
1901void WebPageProxy::remoteInspectorInformationDidChange()
1902{
1903 m_inspectorDebuggable->update();
1904}
1905#endif
1906
1907void WebPageProxy::setBackgroundColor(const std::optional<Color>& color)
1908{
1909 if (m_backgroundColor == color)
1910 return;
1911
1912 m_backgroundColor = color;
1913 if (hasRunningProcess())
1914 send(Messages::WebPage::SetBackgroundColor(color));
1915}
1916
1917void WebPageProxy::setTopContentInset(float contentInset)
1918{
1919 if (m_topContentInset == contentInset)
1920 return;
1921
1922 m_topContentInset = contentInset;
1923
1924 if (!hasRunningProcess())
1925 return;
1926#if PLATFORM(COCOA)
1927 send(Messages::WebPage::SetTopContentInsetFenced(contentInset, m_drawingArea->createFence()));
1928#else
1929 send(Messages::WebPage::SetTopContentInset(contentInset));
1930#endif
1931}
1932
1933void WebPageProxy::setUnderlayColor(const Color& color)
1934{
1935 if (m_underlayColor == color)
1936 return;
1937
1938 m_underlayColor = color;
1939
1940 if (hasRunningProcess())
1941 send(Messages::WebPage::SetUnderlayColor(color));
1942}
1943
1944Color WebPageProxy::underPageBackgroundColor() const
1945{
1946 if (m_underPageBackgroundColorOverride.isValid())
1947 return m_underPageBackgroundColorOverride;
1948
1949 if (m_pageExtendedBackgroundColor.isValid())
1950 return m_pageExtendedBackgroundColor;
1951
1952 return platformUnderPageBackgroundColor();
1953}
1954
1955void WebPageProxy::setUnderPageBackgroundColorOverride(Color&& newUnderPageBackgroundColorOverride)
1956{
1957 if (newUnderPageBackgroundColorOverride == m_underPageBackgroundColorOverride)
1958 return;
1959
1960 auto oldUnderPageBackgroundColor = underPageBackgroundColor();
1961 auto oldUnderPageBackgroundColorOverride = std::exchange(m_underPageBackgroundColorOverride, newUnderPageBackgroundColorOverride);
1962 bool changesUnderPageBackgroundColor = !equalIgnoringSemanticColor(oldUnderPageBackgroundColor, underPageBackgroundColor());
1963 m_underPageBackgroundColorOverride = WTFMove(oldUnderPageBackgroundColorOverride);
1964
1965 if (changesUnderPageBackgroundColor)
1966 pageClient().underPageBackgroundColorWillChange();
1967
1968 m_underPageBackgroundColorOverride = WTFMove(newUnderPageBackgroundColorOverride);
1969
1970 if (changesUnderPageBackgroundColor)
1971 pageClient().underPageBackgroundColorDidChange();
1972
1973 if (m_hasPendingUnderPageBackgroundColorOverrideToDispatch)
1974 return;
1975
1976 m_hasPendingUnderPageBackgroundColorOverrideToDispatch = true;
1977
1978 RunLoop::main().dispatch([this, weakThis = makeWeakPtr(*this)] {
1979 if (!weakThis)
1980 return;
1981
1982 if (!m_hasPendingUnderPageBackgroundColorOverrideToDispatch)
1983 return;
1984
1985 m_hasPendingUnderPageBackgroundColorOverrideToDispatch = false;
1986
1987 if (m_pageClient)
1988 m_pageClient->didChangeBackgroundColor();
1989
1990 if (hasRunningProcess())
1991 send(Messages::WebPage::SetUnderPageBackgroundColorOverride(m_underPageBackgroundColorOverride));
1992 });
1993}
1994
1995void WebPageProxy::viewWillStartLiveResize()
1996{
1997 if (!hasRunningProcess())
1998 return;
1999
2000 closeOverlayedViews();
2001 send(Messages::WebPage::ViewWillStartLiveResize());
2002}
2003
2004void WebPageProxy::viewWillEndLiveResize()
2005{
2006 if (!hasRunningProcess())
2007 return;
2008 send(Messages::WebPage::ViewWillEndLiveResize());
2009}
2010
2011void WebPageProxy::setViewNeedsDisplay(const Region& region)
2012{
2013 pageClient().setViewNeedsDisplay(region);
2014}
2015
2016void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
2017{
2018 pageClient().requestScroll(scrollPosition, scrollOrigin);
2019}
2020
2021WebCore::FloatPoint WebPageProxy::viewScrollPosition() const
2022{
2023 return pageClient().viewScrollPosition();
2024}
2025
2026void WebPageProxy::setSuppressVisibilityUpdates(bool flag)
2027{
2028 if (m_suppressVisibilityUpdates == flag)
2029 return;
2030 m_suppressVisibilityUpdates = flag;
2031
2032 if (!m_suppressVisibilityUpdates) {
2033#if PLATFORM(COCOA)
2034 scheduleActivityStateUpdate();
2035#else
2036 dispatchActivityStateChange();
2037#endif
2038 }
2039}
2040
2041void WebPageProxy::updateActivityState(OptionSet<ActivityState::Flag> flagsToUpdate)
2042{
2043 bool wasVisible = isViewVisible();
2044 m_activityState.remove(flagsToUpdate);
2045 if (flagsToUpdate & ActivityState::IsFocused && pageClient().isViewFocused())
2046 m_activityState.add(ActivityState::IsFocused);
2047 if (flagsToUpdate & ActivityState::WindowIsActive && pageClient().isViewWindowActive())
2048 m_activityState.add(ActivityState::WindowIsActive);
2049 if (flagsToUpdate & ActivityState::IsVisible) {
2050 bool isNowVisible = pageClient().isViewVisible();
2051 if (isNowVisible)
2052 m_activityState.add(ActivityState::IsVisible);
2053 if (wasVisible != isNowVisible)
2054 WEBPAGEPROXY_RELEASE_LOG(ViewState, "updateActivityState: view visibility state changed %d -> %d", wasVisible, isNowVisible);
2055 }
2056 if (flagsToUpdate & ActivityState::IsVisibleOrOccluded && pageClient().isViewVisibleOrOccluded())
2057 m_activityState.add(ActivityState::IsVisibleOrOccluded);
2058 if (flagsToUpdate & ActivityState::IsInWindow && pageClient().isViewInWindow())
2059 m_activityState.add(ActivityState::IsInWindow);
2060 if (flagsToUpdate & ActivityState::IsVisuallyIdle && pageClient().isVisuallyIdle())
2061 m_activityState.add(ActivityState::IsVisuallyIdle);
2062 if (flagsToUpdate & ActivityState::IsAudible && m_mediaState.contains(MediaProducer::MediaState::IsPlayingAudio) && !(m_mutedState.contains(MediaProducer::MutedState::AudioIsMuted)))
2063 m_activityState.add(ActivityState::IsAudible);
2064 if (flagsToUpdate & ActivityState::IsLoading && m_pageLoadState.isLoading())
2065 m_activityState.add(ActivityState::IsLoading);
2066 if (flagsToUpdate & ActivityState::IsCapturingMedia && m_mediaState.containsAny({ MediaProducer::MediaState::HasActiveAudioCaptureDevice, MediaProducer::MediaState::HasActiveVideoCaptureDevice }))
2067 m_activityState.add(ActivityState::IsCapturingMedia);
2068}
2069
2070void WebPageProxy::activityStateDidChange(OptionSet<ActivityState::Flag> mayHaveChanged, ActivityStateChangeDispatchMode dispatchMode, ActivityStateChangeReplyMode replyMode)
2071{
2072 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " activityStateDidChange - mayHaveChanged " << mayHaveChanged);
2073
2074 m_potentiallyChangedActivityStateFlags.add(mayHaveChanged);
2075 m_activityStateChangeWantsSynchronousReply = m_activityStateChangeWantsSynchronousReply || replyMode == ActivityStateChangeReplyMode::Synchronous;
2076
2077 if (m_suppressVisibilityUpdates && dispatchMode != ActivityStateChangeDispatchMode::Immediate)
2078 return;
2079
2080#if PLATFORM(COCOA)
2081 bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ActivityState::IsInWindow) && pageClient().isViewInWindow();
2082 if (dispatchMode == ActivityStateChangeDispatchMode::Immediate || isNewlyInWindow) {
2083 dispatchActivityStateChange();
2084 return;
2085 }
2086 scheduleActivityStateUpdate();
2087#else
2088 UNUSED_PARAM(dispatchMode);
2089 dispatchActivityStateChange();
2090#endif
2091}
2092
2093void WebPageProxy::viewDidLeaveWindow()
2094{
2095 closeOverlayedViews();
2096#if ENABLE(VIDEO_PRESENTATION_MODE)
2097 // When leaving the current page, close the video fullscreen.
2098 if (m_videoFullscreenManager && m_videoFullscreenManager->hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModeStandard))
2099 m_videoFullscreenManager->requestHideAndExitFullscreen();
2100#endif
2101}
2102
2103void WebPageProxy::viewDidEnterWindow()
2104{
2105 LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
2106 if (m_layerHostingMode != layerHostingMode) {
2107 m_layerHostingMode = layerHostingMode;
2108 send(Messages::WebPage::SetLayerHostingMode(layerHostingMode));
2109 }
2110}
2111
2112void WebPageProxy::dispatchActivityStateChange()
2113{
2114#if PLATFORM(COCOA)
2115 if (m_activityStateChangeDispatcher->isScheduled())
2116 m_activityStateChangeDispatcher->invalidate();
2117 m_hasScheduledActivityStateUpdate = false;
2118#endif
2119
2120 if (!hasRunningProcess())
2121 return;
2122
2123 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange - potentiallyChangedActivityStateFlags " << m_potentiallyChangedActivityStateFlags);
2124
2125 // If the visibility state may have changed, then so may the visually idle & occluded agnostic state.
2126 if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)
2127 m_potentiallyChangedActivityStateFlags.add({ ActivityState::IsVisibleOrOccluded, ActivityState::IsVisuallyIdle });
2128
2129 // Record the prior view state, update the flags that may have changed,
2130 // and check which flags have actually changed.
2131 auto previousActivityState = m_activityState;
2132 updateActivityState(m_potentiallyChangedActivityStateFlags);
2133 auto changed = m_activityState ^ previousActivityState;
2134
2135 if (changed)
2136 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange: state changed from " << previousActivityState << " to " << m_activityState);
2137
2138 if ((changed & ActivityState::WindowIsActive) && isViewWindowActive())
2139 updateCurrentModifierState();
2140
2141 if ((m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)) {
2142 if (isViewVisible())
2143 viewIsBecomingVisible();
2144 else
2145 m_process->pageIsBecomingInvisible(m_webPageID);
2146 }
2147
2148 bool isNowInWindow = (changed & ActivityState::IsInWindow) && isInWindow();
2149 // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window.
2150 if (m_viewWasEverInWindow && isNowInWindow) {
2151 if (m_drawingArea->hasVisibleContent() && m_waitsForPaintAfterViewDidMoveToWindow && !m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow)
2152 m_activityStateChangeWantsSynchronousReply = true;
2153 m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = false;
2154 }
2155
2156 // Don't wait synchronously if the view state is not visible. (This matters in particular on iOS, where a hidden page may be suspended.)
2157 if (!(m_activityState & ActivityState::IsVisible))
2158 m_activityStateChangeWantsSynchronousReply = false;
2159
2160 auto activityStateChangeID = m_activityStateChangeWantsSynchronousReply ? takeNextActivityStateChangeID() : static_cast<ActivityStateChangeID>(ActivityStateChangeAsynchronous);
2161
2162 if (changed || activityStateChangeID != ActivityStateChangeAsynchronous || !m_nextActivityStateChangeCallbacks.isEmpty()) {
2163 sendWithAsyncReply(Messages::WebPage::SetActivityState(m_activityState, activityStateChangeID), [callbacks = std::exchange(m_nextActivityStateChangeCallbacks, { })] () mutable {
2164 for (auto& callback : callbacks)
2165 callback();
2166 });
2167 }
2168
2169 // This must happen after the SetActivityState message is sent, to ensure the page visibility event can fire.
2170 updateThrottleState();
2171
2172#if ENABLE(POINTER_LOCK)
2173 if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !pageClient().isViewWindowActive())
2174 || ((changed & ActivityState::IsFocused) && !(m_activityState & ActivityState::IsFocused)))
2175 requestPointerUnlock();
2176#endif
2177
2178 if (changed & ActivityState::IsVisible) {
2179 if (isViewVisible())
2180 m_visiblePageToken = m_process->visiblePageToken();
2181 else {
2182 m_visiblePageToken = nullptr;
2183
2184 // If we've started the responsiveness timer as part of telling the web process to update the backing store
2185 // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we
2186 // stop the unresponsiveness timer here.
2187 m_process->stopResponsivenessTimer();
2188 }
2189 }
2190
2191 if (changed & ActivityState::IsInWindow) {
2192 if (isInWindow())
2193 viewDidEnterWindow();
2194 else
2195 viewDidLeaveWindow();
2196 }
2197
2198 updateBackingStoreDiscardableState();
2199
2200 if (activityStateChangeID != ActivityStateChangeAsynchronous)
2201 waitForDidUpdateActivityState(activityStateChangeID);
2202
2203 m_potentiallyChangedActivityStateFlags = { };
2204 m_activityStateChangeWantsSynchronousReply = false;
2205 m_viewWasEverInWindow |= isNowInWindow;
2206
2207#if PLATFORM(COCOA)
2208 for (auto& callback : m_activityStateUpdateCallbacks)
2209 callback();
2210 m_activityStateUpdateCallbacks.clear();
2211#endif
2212}
2213
2214void WebPageProxy::updateThrottleState()
2215{
2216 bool processSuppressionEnabled = m_preferences->pageVisibilityBasedProcessSuppressionEnabled();
2217
2218 // If process suppression is not enabled take a token on the process pool to disable suppression of support processes.
2219 if (!processSuppressionEnabled)
2220 m_preventProcessSuppressionCount = m_process->processPool().processSuppressionDisabledForPageCount();
2221 else if (!m_preventProcessSuppressionCount)
2222 m_preventProcessSuppressionCount = nullptr;
2223
2224 if (m_activityState & ActivityState::IsVisuallyIdle)
2225 m_pageIsUserObservableCount = nullptr;
2226 else if (!m_pageIsUserObservableCount)
2227 m_pageIsUserObservableCount = m_process->processPool().userObservablePageCount();
2228
2229#if PLATFORM(IOS_FAMILY)
2230 if (isViewVisible()) {
2231 if (!m_isVisibleActivity || !m_isVisibleActivity->isValid()) {
2232 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because the view is visible");
2233 m_isVisibleActivity = m_process->throttler().foregroundActivity("View is visible"_s).moveToUniquePtr();
2234 }
2235 } else if (m_isVisibleActivity) {
2236 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because the view is no longer visible");
2237 m_isVisibleActivity = nullptr;
2238 }
2239
2240 bool isAudible = m_activityState.contains(ActivityState::IsAudible);
2241 if (isAudible) {
2242 if (!m_isAudibleActivity || !m_isAudibleActivity->isValid()) {
2243 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because we are playing audio");
2244 m_isAudibleActivity = m_process->throttler().foregroundActivity("View is playing audio"_s).moveToUniquePtr();
2245 }
2246 m_audibleActivityTimer.stop();
2247 } else if (m_isAudibleActivity) {
2248 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess will release a foreground assertion in %g seconds because we are no longer playing audio", audibleActivityClearDelay.seconds());
2249 if (!m_audibleActivityTimer.isActive())
2250 m_audibleActivityTimer.startOneShot(audibleActivityClearDelay);
2251 }
2252
2253 bool isCapturingMedia = m_activityState.contains(ActivityState::IsCapturingMedia);
2254 if (isCapturingMedia) {
2255 if (!m_isCapturingActivity || !m_isCapturingActivity->isValid()) {
2256 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because media capture is active");
2257 m_isCapturingActivity = m_process->throttler().foregroundActivity("View is capturing media"_s).moveToUniquePtr();
2258 }
2259 } else if (m_isCapturingActivity) {
2260 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because media capture is no longer active");
2261 m_isCapturingActivity = nullptr;
2262 }
2263#endif
2264}
2265
2266#if PLATFORM(IOS_FAMILY)
2267void WebPageProxy::clearAudibleActivity()
2268{
2269 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because we are no longer playing audio");
2270 m_isAudibleActivity = nullptr;
2271}
2272#endif
2273
2274void WebPageProxy::updateHiddenPageThrottlingAutoIncreases()
2275{
2276 if (!m_preferences->hiddenPageDOMTimerThrottlingAutoIncreases())
2277 m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = nullptr;
2278 else if (!m_hiddenPageDOMTimerThrottlingAutoIncreasesCount)
2279 m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = m_process->processPool().hiddenPageThrottlingAutoIncreasesCount();
2280}
2281
2282void WebPageProxy::layerHostingModeDidChange()
2283{
2284 LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
2285 if (m_layerHostingMode == layerHostingMode)
2286 return;
2287
2288 m_layerHostingMode = layerHostingMode;
2289
2290 if (hasRunningProcess())
2291 send(Messages::WebPage::SetLayerHostingMode(layerHostingMode));
2292}
2293
2294void WebPageProxy::waitForDidUpdateActivityState(ActivityStateChangeID activityStateChangeID)
2295{
2296 if (!hasRunningProcess())
2297 return;
2298
2299 if (m_process->state() != WebProcessProxy::State::Running)
2300 return;
2301
2302 // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding.
2303 if (m_waitingForDidUpdateActivityState)
2304 return;
2305
2306#if PLATFORM(IOS_FAMILY)
2307 // Hail Mary check. Should not be possible (dispatchActivityStateChange should force async if not visible,
2308 // and if visible we should be holding an assertion) - but we should never block on a suspended process.
2309 if (!m_isVisibleActivity) {
2310 ASSERT_NOT_REACHED();
2311 return;
2312 }
2313#endif
2314
2315 m_waitingForDidUpdateActivityState = true;
2316
2317 m_drawingArea->waitForDidUpdateActivityState(activityStateChangeID);
2318}
2319
2320IntSize WebPageProxy::viewSize() const
2321{
2322 return pageClient().viewSize();
2323}
2324
2325void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent, CompletionHandler<void()>&& callbackFunction)
2326{
2327 if (!hasRunningProcess()) {
2328 callbackFunction();
2329 return;
2330 }
2331
2332 sendWithAsyncReply(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent), [callbackFunction = WTFMove(callbackFunction), backgroundActivity = m_process->throttler().backgroundActivity("WebPageProxy::setInitialFocus"_s)] () mutable {
2333 callbackFunction();
2334 });
2335}
2336
2337void WebPageProxy::clearSelection()
2338{
2339 if (!hasRunningProcess())
2340 return;
2341 send(Messages::WebPage::ClearSelection());
2342}
2343
2344void WebPageProxy::restoreSelectionInFocusedEditableElement()
2345{
2346 if (!hasRunningProcess())
2347 return;
2348 send(Messages::WebPage::RestoreSelectionInFocusedEditableElement());
2349}
2350
2351void WebPageProxy::validateCommand(const String& commandName, CompletionHandler<void(bool, int32_t)>&& callbackFunction)
2352{
2353 if (!hasRunningProcess())
2354 return callbackFunction(false, 0);
2355
2356 sendWithAsyncReply(Messages::WebPage::ValidateCommand(commandName), WTFMove(callbackFunction));
2357}
2358
2359void WebPageProxy::increaseListLevel()
2360{
2361 if (!hasRunningProcess())
2362 return;
2363
2364 send(Messages::WebPage::IncreaseListLevel());
2365}
2366
2367void WebPageProxy::decreaseListLevel()
2368{
2369 if (!hasRunningProcess())
2370 return;
2371
2372 send(Messages::WebPage::DecreaseListLevel());
2373}
2374
2375void WebPageProxy::changeListType()
2376{
2377 if (!hasRunningProcess())
2378 return;
2379
2380 send(Messages::WebPage::ChangeListType());
2381}
2382
2383void WebPageProxy::setBaseWritingDirection(WritingDirection direction)
2384{
2385 if (!hasRunningProcess())
2386 return;
2387
2388 send(Messages::WebPage::SetBaseWritingDirection(direction));
2389}
2390
2391void WebPageProxy::updateFontAttributesAfterEditorStateChange()
2392{
2393 m_cachedFontAttributesAtSelectionStart.reset();
2394
2395 if (m_editorState.isMissingPostLayoutData)
2396 return;
2397
2398 if (auto fontAttributes = m_editorState.postLayoutData().fontAttributes) {
2399 m_uiClient->didChangeFontAttributes(*fontAttributes);
2400 m_cachedFontAttributesAtSelectionStart = WTFMove(fontAttributes);
2401 }
2402}
2403
2404void WebPageProxy::setNeedsFontAttributes(bool needsFontAttributes)
2405{
2406 if (m_needsFontAttributes == needsFontAttributes)
2407 return;
2408
2409 m_needsFontAttributes = needsFontAttributes;
2410
2411 if (hasRunningProcess())
2412 send(Messages::WebPage::SetNeedsFontAttributes(needsFontAttributes));
2413}
2414
2415bool WebPageProxy::maintainsInactiveSelection() const
2416{
2417 // Regardless of what the client wants to do, keep selections if a local Inspector is open.
2418 // Otherwise, there is no way to use the console to inspect the state of a selection.
2419 if (inspector() && inspector()->isVisible())
2420 return true;
2421
2422 return m_maintainsInactiveSelection;
2423}
2424
2425void WebPageProxy::setMaintainsInactiveSelection(bool newValue)
2426{
2427 m_maintainsInactiveSelection = newValue;
2428}
2429
2430void WebPageProxy::scheduleFullEditorStateUpdate()
2431{
2432 if (!hasRunningProcess())
2433 return;
2434
2435 send(Messages::WebPage::ScheduleFullEditorStateUpdate());
2436}
2437
2438void WebPageProxy::selectAll()
2439{
2440 if (!hasRunningProcess())
2441 return;
2442
2443 send(Messages::WebPage::SelectAll());
2444}
2445
2446static bool isPasteCommandName(const String& commandName)
2447{
2448 static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> pasteCommandNames = HashSet<String, ASCIICaseInsensitiveHash> {
2449 "Paste",
2450 "PasteAndMatchStyle",
2451 "PasteAsQuotation",
2452 "PasteAsPlainText"
2453 };
2454 return pasteCommandNames->contains(commandName);
2455}
2456
2457void WebPageProxy::executeEditCommand(const String& commandName, const String& argument, CompletionHandler<void()>&& callbackFunction)
2458{
2459 if (!hasRunningProcess()) {
2460 callbackFunction();
2461 return;
2462 }
2463
2464 if (isPasteCommandName(commandName))
2465 willPerformPasteCommand();
2466
2467 sendWithAsyncReply(Messages::WebPage::ExecuteEditCommandWithCallback(commandName, argument), [callbackFunction = WTFMove(callbackFunction), backgroundActivity = m_process->throttler().backgroundActivity("WebPageProxy::executeEditCommand"_s)] () mutable {
2468 callbackFunction();
2469 });
2470}
2471
2472void WebPageProxy::executeEditCommand(const String& commandName, const String& argument)
2473{
2474 static NeverDestroyed<String> ignoreSpellingCommandName(MAKE_STATIC_STRING_IMPL("ignoreSpelling"));
2475
2476 if (!hasRunningProcess())
2477 return;
2478
2479 if (isPasteCommandName(commandName))
2480 willPerformPasteCommand();
2481
2482 if (commandName == ignoreSpellingCommandName)
2483 ++m_pendingLearnOrIgnoreWordMessageCount;
2484
2485 send(Messages::WebPage::ExecuteEditCommand(commandName, argument));
2486}
2487
2488void WebPageProxy::requestFontAttributesAtSelectionStart(CompletionHandler<void(const WebCore::FontAttributes&)>&& callback)
2489{
2490 if (!hasRunningProcess())
2491 return callback({ });
2492
2493 sendWithAsyncReply(Messages::WebPage::RequestFontAttributesAtSelectionStart(), [this, protectedThis = makeRef(*this), callback = WTFMove(callback)] (const WebCore::FontAttributes& attributes) mutable {
2494 m_cachedFontAttributesAtSelectionStart = attributes;
2495 callback(attributes);
2496 });
2497}
2498
2499void WebPageProxy::setEditable(bool editable)
2500{
2501 if (editable == m_isEditable)
2502 return;
2503
2504 m_isEditable = editable;
2505
2506 if (!hasRunningProcess())
2507 return;
2508
2509 send(Messages::WebPage::SetEditable(editable));
2510}
2511
2512void WebPageProxy::setMediaStreamCaptureMuted(bool muted)
2513{
2514 auto state = m_mutedState;
2515 if (muted)
2516 state.add(WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2517 else
2518 state.remove(WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2519 setMuted(state);
2520}
2521
2522void WebPageProxy::activateMediaStreamCaptureInPage()
2523{
2524#if ENABLE(MEDIA_STREAM)
2525 WebProcessProxy::muteCaptureInPagesExcept(m_webPageID);
2526#endif
2527 setMediaStreamCaptureMuted(false);
2528}
2529
2530#if !PLATFORM(IOS_FAMILY)
2531void WebPageProxy::didCommitLayerTree(const RemoteLayerTreeTransaction&)
2532{
2533}
2534
2535void WebPageProxy::layerTreeCommitComplete()
2536{
2537}
2538#endif
2539
2540void WebPageProxy::didUpdateRenderingAfterCommittingLoad()
2541{
2542 if (m_hasUpdatedRenderingAfterDidCommitLoad)
2543 return;
2544
2545 m_hasUpdatedRenderingAfterDidCommitLoad = true;
2546 stopMakingViewBlankDueToLackOfRenderingUpdateIfNecessary();
2547}
2548
2549void WebPageProxy::stopMakingViewBlankDueToLackOfRenderingUpdateIfNecessary()
2550{
2551 if (!m_madeViewBlankDueToLackOfRenderingUpdate)
2552 return;
2553
2554 ASSERT(m_hasUpdatedRenderingAfterDidCommitLoad);
2555 WEBPAGEPROXY_RELEASE_LOG(Process, "stopMakingViewBlankDueToLackOfRenderingUpdateIfNecessary:");
2556 pageClient().makeViewBlank(false);
2557 m_madeViewBlankDueToLackOfRenderingUpdate = false;
2558}
2559
2560// If we have not painted yet since the last load commit, then we are likely still displaying the previous page.
2561// Displaying a JS prompt for the new page with the old page behind would be confusing so we make the view blank
2562// until the next paint in such case.
2563void WebPageProxy::makeViewBlankIfUnpaintedSinceLastLoadCommit()
2564{
2565 if (!m_hasUpdatedRenderingAfterDidCommitLoad) {
2566#if PLATFORM(COCOA)
2567 static bool shouldMakeViewBlank = linkedOnOrAfter(WebCore::SDKVersion::FirstWithBlankViewOnJSPrompt);
2568#else
2569 static bool shouldMakeViewBlank = true;
2570#endif
2571 if (shouldMakeViewBlank) {
2572 WEBPAGEPROXY_RELEASE_LOG(Process, "makeViewBlankIfUnpaintedSinceLastLoadCommit: Making the view blank because of a JS prompt before the first paint for its page");
2573 pageClient().makeViewBlank(true);
2574 m_madeViewBlankDueToLackOfRenderingUpdate = true;
2575 }
2576 }
2577}
2578
2579void WebPageProxy::discardQueuedMouseEvents()
2580{
2581 while (m_mouseEventQueue.size() > 1)
2582 m_mouseEventQueue.removeLast();
2583}
2584
2585#if ENABLE(DRAG_SUPPORT)
2586void WebPageProxy::dragEntered(DragData& dragData, const String& dragStorageName)
2587{
2588#if PLATFORM(COCOA)
2589 WebPasteboardProxy::singleton().grantAccessToCurrentTypes(m_process.get(), dragStorageName);
2590#endif
2591 launchInitialProcessIfNecessary();
2592 performDragControllerAction(DragControllerAction::Entered, dragData, dragStorageName, { }, { });
2593}
2594
2595void WebPageProxy::dragUpdated(DragData& dragData, const String& dragStorageName)
2596{
2597#if PLATFORM(COCOA)
2598 WebPasteboardProxy::singleton().grantAccessToCurrentTypes(m_process.get(), dragStorageName);
2599#endif
2600 performDragControllerAction(DragControllerAction::Updated, dragData, dragStorageName, { }, { });
2601}
2602
2603void WebPageProxy::dragExited(DragData& dragData, const String& dragStorageName)
2604{
2605 performDragControllerAction(DragControllerAction::Exited, dragData, dragStorageName, { }, { });
2606}
2607
2608void WebPageProxy::performDragOperation(DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2609{
2610 performDragControllerAction(DragControllerAction::PerformDragOperation, dragData, dragStorageName, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload));
2611}
2612
2613void WebPageProxy::performDragControllerAction(DragControllerAction action, DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2614{
2615 if (!hasRunningProcess())
2616 return;
2617#if PLATFORM(GTK)
2618 UNUSED_PARAM(dragStorageName);
2619 UNUSED_PARAM(sandboxExtensionHandle);
2620 UNUSED_PARAM(sandboxExtensionsForUpload);
2621
2622 String url = dragData.asURL();
2623 if (!url.isEmpty())
2624 m_process->assumeReadAccessToBaseURL(*this, url);
2625
2626 ASSERT(dragData.platformData());
2627 send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), *dragData.platformData(), dragData.flags()));
2628#else
2629 send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload));
2630#endif
2631}
2632
2633void WebPageProxy::didPerformDragControllerAction(std::optional<WebCore::DragOperation> dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect)
2634{
2635 m_currentDragOperation = dragOperation;
2636 m_currentDragHandlingMethod = dragHandlingMethod;
2637 m_currentDragIsOverFileInput = mouseIsOverFileInput;
2638 m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted;
2639 m_currentDragCaretEditableElementRect = editableElementRect;
2640 setDragCaretRect(insertionRect);
2641 pageClient().didPerformDragControllerAction();
2642}
2643
2644#if PLATFORM(GTK)
2645void WebPageProxy::startDrag(SelectionData&& selectionData, OptionSet<WebCore::DragOperation> dragOperationMask, const ShareableBitmap::Handle& dragImageHandle)
2646{
2647 RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr;
2648 pageClient().startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage));
2649
2650 didStartDrag();
2651}
2652#endif
2653
2654void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet<WebCore::DragOperation> dragOperationMask)
2655{
2656 if (!hasRunningProcess())
2657 return;
2658 send(Messages::WebPage::DragEnded(clientPosition, globalPosition, dragOperationMask));
2659 setDragCaretRect({ });
2660}
2661
2662void WebPageProxy::didPerformDragOperation(bool handled)
2663{
2664 pageClient().didPerformDragOperation(handled);
2665}
2666
2667void WebPageProxy::didStartDrag()
2668{
2669 if (!hasRunningProcess())
2670 return;
2671
2672 discardQueuedMouseEvents();
2673 send(Messages::WebPage::DidStartDrag());
2674}
2675
2676void WebPageProxy::dragCancelled()
2677{
2678 if (hasRunningProcess())
2679 send(Messages::WebPage::DragCancelled());
2680}
2681
2682void WebPageProxy::didEndDragging()
2683{
2684 resetCurrentDragInformation();
2685}
2686
2687void WebPageProxy::resetCurrentDragInformation()
2688{
2689 m_currentDragOperation = std::nullopt;
2690 m_currentDragHandlingMethod = DragHandlingMethod::None;
2691 m_currentDragIsOverFileInput = false;
2692 m_currentDragNumberOfFilesToBeAccepted = 0;
2693 setDragCaretRect({ });
2694}
2695
2696#if !PLATFORM(IOS_FAMILY) || !ENABLE(DRAG_SUPPORT)
2697
2698void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
2699{
2700 m_currentDragCaretRect = dragCaretRect;
2701}
2702
2703#endif
2704
2705#endif // ENABLE(DRAG_SUPPORT)
2706
2707static bool removeOldRedundantEvent(Deque<NativeWebMouseEvent>& queue, WebEvent::Type incomingEventType)
2708{
2709 if (incomingEventType != WebEvent::MouseMove && incomingEventType != WebEvent::MouseForceChanged)
2710 return false;
2711
2712 auto it = queue.rbegin();
2713 auto end = queue.rend();
2714
2715 // Must not remove the first event in the deque, since it is already being dispatched.
2716 if (it != end)
2717 --end;
2718
2719 for (; it != end; ++it) {
2720 auto type = it->type();
2721 if (type == incomingEventType) {
2722 queue.remove(--it.base());
2723 return true;
2724 }
2725 if (type != WebEvent::MouseMove && type != WebEvent::MouseForceChanged)
2726 break;
2727 }
2728 return false;
2729}
2730
2731void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event)
2732{
2733 if (event.type() == WebEvent::MouseDown)
2734 launchInitialProcessIfNecessary();
2735
2736 if (!hasRunningProcess())
2737 return;
2738
2739#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2740 if (m_scrollingCoordinatorProxy)
2741 m_scrollingCoordinatorProxy->handleMouseEvent(platform(event));
2742#endif
2743
2744 // If we receive multiple mousemove or mouseforcechanged events and the most recent mousemove or mouseforcechanged event
2745 // (respectively) has not yet been sent to WebProcess for processing, remove the pending mouse event and insert the new
2746 // event in the queue.
2747 bool didRemoveEvent = removeOldRedundantEvent(m_mouseEventQueue, event.type());
2748 m_mouseEventQueue.append(event);
2749
2750#if LOG_DISABLED
2751 UNUSED_PARAM(didRemoveEvent);
2752#else
2753 LOG(MouseHandling, "UIProcess: %s mouse event %s (queue size %zu)", didRemoveEvent ? "replaced" : "enqueued", webMouseEventTypeString(event.type()), m_mouseEventQueue.size());
2754#endif
2755
2756 if (m_mouseEventQueue.size() == 1) // Otherwise, called from DidReceiveEvent message handler.
2757 processNextQueuedMouseEvent();
2758}
2759
2760void WebPageProxy::processNextQueuedMouseEvent()
2761{
2762 if (!hasRunningProcess())
2763 return;
2764
2765 ASSERT(!m_mouseEventQueue.isEmpty());
2766
2767 const NativeWebMouseEvent& event = m_mouseEventQueue.first();
2768
2769 if (pageClient().windowIsFrontWindowUnderMouse(event))
2770 setToolTip(String());
2771
2772 WebEvent::Type eventType = event.type();
2773 if (eventType == WebEvent::MouseDown || eventType == WebEvent::MouseForceChanged || eventType == WebEvent::MouseForceDown)
2774 m_process->startResponsivenessTimer(WebProcessProxy::UseLazyStop::Yes);
2775 else if (eventType != WebEvent::MouseMove) {
2776 // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction.
2777 m_process->startResponsivenessTimer();
2778 }
2779
2780 std::optional<SandboxExtension::HandleArray> sandboxExtensions;
2781
2782#if PLATFORM(MAC)
2783 bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEvent::MouseMove && event.button() != WebMouseEvent::Button::NoButton;
2784 if (eventMayStartDrag)
2785 sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, std::nullopt);
2786#endif
2787
2788 LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size());
2789 send(Messages::WebPage::MouseEvent(event, sandboxExtensions));
2790}
2791
2792void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function<void ()>&& action)
2793{
2794 if (!isProcessingMouseEvents()) {
2795 action();
2796 return;
2797 }
2798
2799 m_callbackHandlersAfterProcessingPendingMouseEvents.append(WTFMove(action));
2800}
2801
2802void WebPageProxy::didFinishProcessingAllPendingMouseEvents()
2803{
2804 flushPendingMouseEventCallbacks();
2805}
2806
2807void WebPageProxy::flushPendingMouseEventCallbacks()
2808{
2809 for (auto& callback : m_callbackHandlersAfterProcessingPendingMouseEvents)
2810 callback();
2811
2812 m_callbackHandlersAfterProcessingPendingMouseEvents.clear();
2813}
2814
2815void WebPageProxy::dispatchWheelEventWithoutScrolling(const WebWheelEvent& event, CompletionHandler<void(bool)>&& completionHandler)
2816{
2817 sendWithAsyncReply(Messages::WebPage::DispatchWheelEventWithoutScrolling(event), WTFMove(completionHandler));
2818}
2819
2820void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
2821{
2822#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2823 if (m_scrollingCoordinatorProxy && m_scrollingCoordinatorProxy->handleWheelEvent(platform(event)))
2824 return;
2825#endif
2826
2827 if (!hasRunningProcess())
2828 return;
2829
2830 closeOverlayedViews();
2831
2832 if (wheelEventCoalescer().shouldDispatchEvent(event)) {
2833 auto event = wheelEventCoalescer().nextEventToDispatch();
2834 sendWheelEvent(*event);
2835 }
2836}
2837
2838#if HAVE(CVDISPLAYLINK)
2839void WebPageProxy::wheelEventHysteresisUpdated(PAL::HysteresisState state)
2840{
2841 if (!m_process->hasConnection() || !m_displayID)
2842 return;
2843
2844 bool wantsFullSpeedUpdates = state == PAL::HysteresisState::Started;
2845 process().processPool().setDisplayLinkForDisplayWantsFullSpeedUpdates(*m_process->connection(), *m_displayID, wantsFullSpeedUpdates);
2846}
2847#endif
2848
2849void WebPageProxy::updateWheelEventActivityAfterProcessSwap()
2850{
2851#if HAVE(CVDISPLAYLINK)
2852 if (m_wheelEventActivityHysteresis.state() == PAL::HysteresisState::Started) {
2853 if (!m_process->hasConnection() || !m_displayID)
2854 return;
2855
2856 bool wantsFullSpeedUpdates = true;
2857 process().processPool().setDisplayLinkForDisplayWantsFullSpeedUpdates(*m_process->connection(), *m_displayID, wantsFullSpeedUpdates);
2858 }
2859#endif
2860}
2861
2862void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
2863{
2864#if HAVE(CVDISPLAYLINK)
2865 m_wheelEventActivityHysteresis.impulse();
2866#endif
2867
2868 send(
2869 Messages::EventDispatcher::WheelEvent(
2870 m_webPageID,
2871 event,
2872 shouldUseImplicitRubberBandControl() ? !m_backForwardList->backItem() : rubberBandsAtLeft(),
2873 shouldUseImplicitRubberBandControl() ? !m_backForwardList->forwardItem() : rubberBandsAtRight(),
2874 rubberBandsAtTop(),
2875 rubberBandsAtBottom()
2876 ), 0);
2877
2878 // Manually ping the web process to check for responsiveness since our wheel
2879 // event will dispatch to a non-main thread, which always responds.
2880 m_process->isResponsiveWithLazyStop();
2881}
2882
2883WebWheelEventCoalescer& WebPageProxy::wheelEventCoalescer()
2884{
2885 if (!m_wheelEventCoalescer) {
2886 m_wheelEventCoalescer = makeUnique<WebWheelEventCoalescer>();
2887 m_wheelEventCoalescer->setShouldCoalesceEventsDuringDeceleration(shouldCoalesceWheelEventsDuringDeceleration());
2888 }
2889
2890 return *m_wheelEventCoalescer;
2891}
2892
2893bool WebPageProxy::shouldCoalesceWheelEventsDuringDeceleration() const
2894{
2895#if HAVE(CVDISPLAYLINK)
2896 if (!m_displayID)
2897 return false;
2898
2899 auto framesPerSecond = m_process->processPool().nominalFramesPerSecondForDisplay(*m_displayID);
2900 return framesPerSecond > WebCore::FullSpeedFramesPerSecond;
2901#else
2902 return false;
2903#endif
2904}
2905
2906bool WebPageProxy::hasQueuedKeyEvent() const
2907{
2908 return !m_keyEventQueue.isEmpty();
2909}
2910
2911const NativeWebKeyboardEvent& WebPageProxy::firstQueuedKeyEvent() const
2912{
2913 return m_keyEventQueue.first();
2914}
2915
2916bool WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
2917{
2918 if (!hasRunningProcess())
2919 return false;
2920
2921 LOG(KeyHandling, "WebPageProxy::handleKeyboardEvent: %s", webKeyboardEventTypeString(event.type()));
2922
2923 m_keyEventQueue.append(event);
2924
2925 m_process->startResponsivenessTimer(event.type() == WebEvent::KeyDown ? WebProcessProxy::UseLazyStop::Yes : WebProcessProxy::UseLazyStop::No);
2926
2927 if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler.
2928 LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent");
2929 send(Messages::WebPage::KeyEvent(event));
2930 }
2931
2932 return true;
2933}
2934
2935WebPreferencesStore WebPageProxy::preferencesStore() const
2936{
2937 return m_preferences->store();
2938}
2939
2940#if ENABLE(NETSCAPE_PLUGIN_API)
2941void WebPageProxy::findPlugin(const String& mimeType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, Messages::WebPageProxy::FindPlugin::DelayedReply&& reply)
2942{
2943 PageClientProtector protector(pageClient());
2944
2945 MESSAGE_CHECK_URL(m_process, urlString);
2946
2947 URL pluginURL = URL { URL(), urlString };
2948 String newMimeType = mimeType.convertToASCIILowercase();
2949
2950 PluginData::AllowedPluginTypes allowedPluginTypes = allowOnlyApplicationPlugins ? PluginData::OnlyApplicationPlugins : PluginData::AllPlugins;
2951
2952 URL pageURL = URL { URL(), pageURLString };
2953 if (!m_process->processPool().pluginInfoStore().isSupportedPlugin(mimeType, pluginURL, frameURLString, pageURL)) {
2954 reply(0, newMimeType, PluginModuleLoadNormally, { }, true);
2955 return;
2956 }
2957
2958 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, pluginURL, allowedPluginTypes);
2959 if (!plugin.path) {
2960 reply(0, newMimeType, PluginModuleLoadNormally, { }, false);
2961 return;
2962 }
2963
2964 uint32_t pluginLoadPolicy = PluginInfoStore::defaultLoadPolicyForPlugin(plugin);
2965
2966#if PLATFORM(COCOA)
2967 auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, String(), pageURLString, String(), String());
2968#endif
2969
2970 auto findPluginCompletion = [reply = WTFMove(reply), newMimeType = WTFMove(newMimeType), plugin = WTFMove(plugin)] (uint32_t pluginLoadPolicy, const String& unavailabilityDescription) mutable {
2971 PluginProcessSandboxPolicy pluginProcessSandboxPolicy = PluginProcessSandboxPolicy::Normal;
2972 switch (pluginLoadPolicy) {
2973 case PluginModuleLoadNormally:
2974 pluginProcessSandboxPolicy = PluginProcessSandboxPolicy::Normal;
2975 break;
2976 case PluginModuleLoadUnsandboxed:
2977 pluginProcessSandboxPolicy = PluginProcessSandboxPolicy::Unsandboxed;
2978 break;
2979
2980 case PluginModuleBlockedForSecurity:
2981 case PluginModuleBlockedForCompatibility:
2982 reply(0, newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2983 return;
2984 }
2985
2986 reply(PluginProcessManager::singleton().pluginProcessToken(plugin, pluginProcessSandboxPolicy), newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2987 };
2988
2989#if PLATFORM(COCOA)
2990 m_navigationClient->decidePolicyForPluginLoad(*this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), WTFMove(findPluginCompletion));
2991#else
2992 findPluginCompletion(pluginLoadPolicy, { });
2993#endif
2994}
2995
2996#endif // ENABLE(NETSCAPE_PLUGIN_API)
2997
2998#if ENABLE(TOUCH_EVENTS)
2999
3000static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b)
3001{
3002 if (static_cast<uintptr_t>(b) > static_cast<uintptr_t>(a))
3003 return b;
3004 return a;
3005}
3006
3007void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent)
3008{
3009#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
3010 const EventNames& names = eventNames();
3011 for (auto& touchPoint : touchStartEvent.touchPoints()) {
3012 IntPoint location = touchPoint.location();
3013 auto updateTrackingType = [this, location](TrackingType& trackingType, const AtomString& eventName) {
3014 if (trackingType == TrackingType::Synchronous)
3015 return;
3016
3017 TrackingType trackingTypeForLocation = m_scrollingCoordinatorProxy->eventTrackingTypeForPoint(eventName, location);
3018
3019 trackingType = mergeTrackingTypes(trackingType, trackingTypeForLocation);
3020 };
3021 updateTrackingType(m_touchAndPointerEventTracking.touchForceChangedTracking, names.touchforcechangeEvent);
3022 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.touchstartEvent);
3023 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.touchmoveEvent);
3024 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.touchendEvent);
3025 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointeroverEvent);
3026 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerenterEvent);
3027 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerdownEvent);
3028 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.pointermoveEvent);
3029 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerupEvent);
3030 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointeroutEvent);
3031 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerleaveEvent);
3032 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.mousedownEvent);
3033 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.mousemoveEvent);
3034 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.mouseupEvent);
3035 }
3036#else
3037 UNUSED_PARAM(touchStartEvent);
3038 m_touchAndPointerEventTracking.touchForceChangedTracking = TrackingType::Synchronous;
3039 m_touchAndPointerEventTracking.touchStartTracking = TrackingType::Synchronous;
3040 m_touchAndPointerEventTracking.touchMoveTracking = TrackingType::Synchronous;
3041 m_touchAndPointerEventTracking.touchEndTracking = TrackingType::Synchronous;
3042#endif // ENABLE(ASYNC_SCROLLING)
3043}
3044
3045TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const
3046{
3047 // We send all events if any type is needed, we just do it asynchronously for the types that are not tracked.
3048 //
3049 // Touch events define a sequence with strong dependencies. For example, we can expect
3050 // a TouchMove to only appear after a TouchStart, and the ids of the touch points is consistent between
3051 // the two.
3052 //
3053 // WebCore should not have to set up its state correctly after some events were dismissed.
3054 // For example, we don't want to send a TouchMoved without a TouchPressed.
3055 // We send everything, WebCore updates its internal state and dispatch what is needed to the page.
3056 TrackingType globalTrackingType = m_touchAndPointerEventTracking.isTrackingAnything() ? TrackingType::Asynchronous : TrackingType::NotTracking;
3057
3058 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchForceChangedTracking);
3059 for (auto& touchPoint : touchStartEvent.touchPoints()) {
3060 switch (touchPoint.state()) {
3061 case WebPlatformTouchPoint::TouchReleased:
3062 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchEndTracking);
3063 break;
3064 case WebPlatformTouchPoint::TouchPressed:
3065 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchStartTracking);
3066 break;
3067 case WebPlatformTouchPoint::TouchMoved:
3068 case WebPlatformTouchPoint::TouchStationary:
3069 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchMoveTracking);
3070 break;
3071 case WebPlatformTouchPoint::TouchCancelled:
3072 globalTrackingType = mergeTrackingTypes(globalTrackingType, TrackingType::Asynchronous);
3073 break;
3074 }
3075 }
3076
3077 return globalTrackingType;
3078}
3079
3080#endif
3081
3082#if ENABLE(MAC_GESTURE_EVENTS)
3083void WebPageProxy::handleGestureEvent(const NativeWebGestureEvent& event)
3084{
3085 if (!hasRunningProcess())
3086 return;
3087
3088 m_gestureEventQueue.append(event);
3089 // FIXME: Consider doing some coalescing here.
3090
3091 m_process->startResponsivenessTimer((event.type() == WebEvent::GestureStart || event.type() == WebEvent::GestureChange) ? WebProcessProxy::UseLazyStop::Yes : WebProcessProxy::UseLazyStop::No);
3092
3093 send(Messages::EventDispatcher::GestureEvent(m_webPageID, event), 0);
3094}
3095#endif
3096
3097#if ENABLE(IOS_TOUCH_EVENTS)
3098void WebPageProxy::handlePreventableTouchEvent(NativeWebTouchEvent& event)
3099{
3100 if (!hasRunningProcess())
3101 return;
3102
3103 TraceScope scope(SyncTouchEventStart, SyncTouchEventEnd);
3104
3105 updateTouchEventTracking(event);
3106
3107 auto handleAllTouchPointsReleased = WTF::makeScopeExit([&] {
3108 if (!event.allTouchPointsAreReleased())
3109 return;
3110
3111 m_touchAndPointerEventTracking.reset();
3112 didReleaseAllTouchPoints();
3113 });
3114
3115 bool isTouchStart = event.type() == WebEvent::TouchStart;
3116 bool isTouchEnd = event.type() == WebEvent::TouchEnd;
3117
3118 TrackingType touchEventsTrackingType = touchEventTrackingType(event);
3119 if (touchEventsTrackingType == TrackingType::NotTracking) {
3120 if (isTouchStart)
3121 pageClient().doneDeferringTouchStart(false);
3122 if (isTouchEnd)
3123 pageClient().doneDeferringTouchEnd(false);
3124 return;
3125 }
3126
3127 if (touchEventsTrackingType == TrackingType::Asynchronous) {
3128 // We can end up here if a native gesture has not started but the event handlers are passive.
3129 //
3130 // The client of WebPageProxy asks the event to be sent synchronously since the touch event
3131 // can prevent a native gesture.
3132 // But, here we know that all events handlers that can handle this events are passive.
3133 // We can use asynchronous dispatch and pretend to the client that the page does nothing with the events.
3134 event.setCanPreventNativeGestures(false);
3135 handleUnpreventableTouchEvent(event);
3136 didReceiveEvent(event.type(), false);
3137 if (isTouchStart)
3138 pageClient().doneDeferringTouchStart(false);
3139 if (isTouchEnd)
3140 pageClient().doneDeferringTouchEnd(false);
3141 return;
3142 }
3143
3144 if (isTouchStart || isTouchEnd) {
3145 if (isTouchStart)
3146 ++m_handlingPreventableTouchStartCount;
3147
3148 if (isTouchEnd)
3149 ++m_handlingPreventableTouchEndCount;
3150
3151 sendWithAsyncReply(Messages::EventDispatcher::TouchEvent(m_webPageID, event), [this, weakThis = makeWeakPtr(*this), event] (bool handled) {
3152 auto protectedThis = makeRefPtr(weakThis.get());
3153 if (!protectedThis)
3154 return;
3155
3156 bool didFinishDeferringTouchStart = false;
3157 ASSERT_IMPLIES(event.type() == WebEvent::TouchStart, m_handlingPreventableTouchStartCount);
3158 if (event.type() == WebEvent::TouchStart && m_handlingPreventableTouchStartCount)
3159 didFinishDeferringTouchStart = !--m_handlingPreventableTouchStartCount;
3160
3161 bool didFinishDeferringTouchEnd = false;
3162 ASSERT_IMPLIES(event.type() == WebEvent::TouchEnd, m_handlingPreventableTouchEndCount);
3163 if (event.type() == WebEvent::TouchEnd && m_handlingPreventableTouchEndCount)
3164 didFinishDeferringTouchEnd = !--m_handlingPreventableTouchEndCount;
3165
3166 bool handledOrFailedWithError = handled || m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart;
3167 if (!isHandlingPreventableTouchStart())
3168 m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = false;
3169
3170 didReceiveEvent(event.type(), handledOrFailedWithError);
3171 if (!m_pageClient)
3172 return;
3173
3174 pageClient().doneWithTouchEvent(event, handledOrFailedWithError);
3175
3176 if (didFinishDeferringTouchStart)
3177 pageClient().doneDeferringTouchStart(handledOrFailedWithError);
3178
3179 if (didFinishDeferringTouchEnd)
3180 pageClient().doneDeferringTouchEnd(handledOrFailedWithError);
3181 });
3182 return;
3183 }
3184
3185 m_process->startResponsivenessTimer();
3186 bool handled = false;
3187 bool replyReceived = !!sendSync(Messages::WebPage::TouchEventSync(event), Messages::WebPage::TouchEventSync::Reply(handled), 1_s, IPC::SendSyncOption::ForceDispatchWhenDestinationIsWaitingForUnboundedSyncReply);
3188 // If the sync request has timed out, we should consider the event handled. The Web Process is too busy to answer any questions, so the default action is also likely to have issues.
3189 if (!replyReceived)
3190 handled = true;
3191 didReceiveEvent(event.type(), handled);
3192 pageClient().doneWithTouchEvent(event, handled);
3193 if (!isHandlingPreventableTouchStart())
3194 pageClient().doneDeferringTouchStart(handled);
3195 else if (handled)
3196 m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = true;
3197 m_process->stopResponsivenessTimer();
3198}
3199
3200void WebPageProxy::resetPotentialTapSecurityOrigin()
3201{
3202 if (!hasRunningProcess())
3203 return;
3204
3205 send(Messages::WebPage::ResetPotentialTapSecurityOrigin());
3206}
3207
3208void WebPageProxy::handleUnpreventableTouchEvent(const NativeWebTouchEvent& event)
3209{
3210 if (!hasRunningProcess())
3211 return;
3212
3213 TrackingType touchEventsTrackingType = touchEventTrackingType(event);
3214 if (touchEventsTrackingType == TrackingType::NotTracking)
3215 return;
3216
3217 send(Messages::EventDispatcher::TouchEventWithoutCallback(m_webPageID, event), 0);
3218
3219 if (event.allTouchPointsAreReleased()) {
3220 m_touchAndPointerEventTracking.reset();
3221 didReleaseAllTouchPoints();
3222 }
3223}
3224
3225#elif ENABLE(TOUCH_EVENTS)
3226void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event)
3227{
3228 if (!hasRunningProcess())
3229 return;
3230
3231 updateTouchEventTracking(event);
3232
3233 if (touchEventTrackingType(event) == TrackingType::NotTracking)
3234 return;
3235
3236 // If the page is suspended, which should be the case during panning, pinching
3237 // and animation on the page itself (kinetic scrolling, tap to zoom) etc, then
3238 // we do not send any of the events to the page even if is has listeners.
3239 if (!m_areActiveDOMObjectsAndAnimationsSuspended) {
3240 m_touchEventQueue.append(event);
3241 m_process->startResponsivenessTimer();
3242 send(Messages::WebPage::TouchEvent(event));
3243 } else {
3244 if (m_touchEventQueue.isEmpty()) {
3245 bool isEventHandled = false;
3246 pageClient().doneWithTouchEvent(event, isEventHandled);
3247 } else {
3248 // We attach the incoming events to the newest queued event so that all
3249 // the events are delivered in the correct order when the event is dequed.
3250 QueuedTouchEvents& lastEvent = m_touchEventQueue.last();
3251 lastEvent.deferredTouchEvents.append(event);
3252 }
3253 }
3254
3255 if (event.allTouchPointsAreReleased()) {
3256 m_touchAndPointerEventTracking.reset();
3257 didReleaseAllTouchPoints();
3258 }
3259}
3260#endif // ENABLE(TOUCH_EVENTS)
3261
3262void WebPageProxy::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
3263{
3264 send(Messages::WebPage::CancelPointer(pointerId, documentPoint));
3265}
3266
3267void WebPageProxy::touchWithIdentifierWasRemoved(WebCore::PointerID pointerId)
3268{
3269 send(Messages::WebPage::TouchWithIdentifierWasRemoved(pointerId));
3270}
3271
3272void WebPageProxy::scrollBy(ScrollDirection direction, ScrollGranularity granularity)
3273{
3274 if (!hasRunningProcess())
3275 return;
3276
3277 send(Messages::WebPage::ScrollBy(direction, granularity));
3278}
3279
3280void WebPageProxy::centerSelectionInVisibleArea()
3281{
3282 if (!hasRunningProcess())
3283 return;
3284
3285 send(Messages::WebPage::CenterSelectionInVisibleArea());
3286}
3287
3288class WebPageProxy::PolicyDecisionSender : public RefCounted<PolicyDecisionSender> {
3289public:
3290 using SendFunction = CompletionHandler<void(PolicyDecision&&)>;
3291
3292 static Ref<PolicyDecisionSender> create(PolicyCheckIdentifier identifier, SendFunction&& sendFunction)
3293 {
3294 return adoptRef(*new PolicyDecisionSender(identifier, WTFMove(sendFunction)));
3295 }
3296
3297 void send(PolicyDecision&& policyDecision)
3298 {
3299 if (m_sendFunction)
3300 m_sendFunction(WTFMove(policyDecision));
3301 }
3302
3303 PolicyCheckIdentifier identifier() { return m_identifier; }
3304
3305private:
3306 PolicyDecisionSender(PolicyCheckIdentifier identifier, SendFunction sendFunction)
3307 : m_sendFunction(WTFMove(sendFunction))
3308 , m_identifier(identifier)
3309 { }
3310
3311 SendFunction m_sendFunction;
3312 PolicyCheckIdentifier m_identifier;
3313};
3314
3315#if ENABLE(APP_BOUND_DOMAINS)
3316static bool shouldTreatURLProtocolAsAppBound(const URL& requestURL)
3317{
3318 return requestURL.protocolIsAbout() || requestURL.protocolIsData() || requestURL.protocolIsBlob() || requestURL.isLocalFile() || requestURL.protocolIsJavaScript();
3319}
3320
3321bool WebPageProxy::setIsNavigatingToAppBoundDomainAndCheckIfPermitted(bool isMainFrame, const URL& requestURL, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain)
3322{
3323 if (isFullWebBrowser()) {
3324 if (hasProhibitedUsageStrings())
3325 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
3326 return true;
3327 }
3328
3329 if (!isNavigatingToAppBoundDomain) {
3330 m_isNavigatingToAppBoundDomain = std::nullopt;
3331 return true;
3332 }
3333 if (m_ignoresAppBoundDomains)
3334 return true;
3335
3336 if (isMainFrame && shouldTreatURLProtocolAsAppBound(requestURL)) {
3337 isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::Yes;
3338 m_limitsNavigationsToAppBoundDomains = true;
3339 }
3340 if (m_limitsNavigationsToAppBoundDomains) {
3341 if (*isNavigatingToAppBoundDomain == NavigatingToAppBoundDomain::No) {
3342 if (isMainFrame)
3343 return false;
3344 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
3345 return true;
3346 }
3347 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::Yes;
3348 } else {
3349 if (m_hasExecutedAppBoundBehaviorBeforeNavigation)
3350 return false;
3351 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
3352 }
3353 return true;
3354}
3355
3356void WebPageProxy::isNavigatingToAppBoundDomainTesting(CompletionHandler<void(bool)>&& completionHandler)
3357{
3358 completionHandler(m_isNavigatingToAppBoundDomain && (*m_isNavigatingToAppBoundDomain == NavigatingToAppBoundDomain::Yes));
3359}
3360
3361void WebPageProxy::isForcedIntoAppBoundModeTesting(CompletionHandler<void(bool)>&& completionHandler)
3362{
3363 completionHandler(m_limitsNavigationsToAppBoundDomains);
3364}
3365#endif
3366
3367void WebPageProxy::disableServiceWorkerEntitlementInNetworkProcess()
3368{
3369#if ENABLE(APP_BOUND_DOMAINS) && !PLATFORM(MACCATALYST)
3370 websiteDataStore().networkProcess().send(Messages::NetworkProcess::DisableServiceWorkerEntitlement(), 0);
3371#endif
3372}
3373
3374void WebPageProxy::clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&& completionHandler)
3375{
3376#if ENABLE(APP_BOUND_DOMAINS) && !PLATFORM(MACCATALYST)
3377 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
3378 sendWithAsyncReply(Messages::WebPage::ClearServiceWorkerEntitlementOverride(), [callbackAggregator] { });
3379 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::ClearServiceWorkerEntitlementOverride(), [callbackAggregator] { });
3380#else
3381 completionHandler();
3382#endif
3383}
3384
3385void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, API::Navigation* navigation, Ref<API::NavigationAction>&& navigationAction, ProcessSwapRequestedByClient processSwapRequestedByClient, WebFrameProxy& frame, RefPtr<API::WebsitePolicies>&& policies, Ref<PolicyDecisionSender>&& sender)
3386{
3387 WEBPAGEPROXY_RELEASE_LOG(Loading, "receivedNavigationPolicyDecision: frameID=%llu, navigationID=%llu, policyAction=%u", frame.frameID().toUInt64(), navigation ? navigation->navigationID() : 0, (unsigned)policyAction);
3388
3389 Ref<WebsiteDataStore> websiteDataStore = m_websiteDataStore.copyRef();
3390 if (policies) {
3391 if (policies->websiteDataStore() && policies->websiteDataStore() != websiteDataStore.ptr()) {
3392 websiteDataStore = *policies->websiteDataStore();
3393 processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
3394 }
3395 if (policies->userContentController() && policies->userContentController() != m_userContentController.ptr())
3396 processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
3397 }
3398
3399 if (navigation && !navigation->userContentExtensionsEnabled()) {
3400 if (!policies)
3401 policies = API::WebsitePolicies::create();
3402 policies->setContentBlockersEnabled(false);
3403 }
3404
3405#if ENABLE(DEVICE_ORIENTATION)
3406 if (navigation && (!policies || policies->deviceOrientationAndMotionAccessState() == WebCore::DeviceOrientationOrMotionPermissionState::Prompt)) {
3407 auto deviceOrientationPermission = websiteDataStore->deviceOrientationAndMotionAccessController().cachedDeviceOrientationPermission(SecurityOriginData::fromURL(navigation->currentRequest().url()));
3408 if (deviceOrientationPermission != WebCore::DeviceOrientationOrMotionPermissionState::Prompt) {
3409 if (!policies)
3410 policies = API::WebsitePolicies::create();
3411 policies->setDeviceOrientationAndMotionAccessState(deviceOrientationPermission);
3412 }
3413 }
3414#endif
3415
3416#if PLATFORM(COCOA)
3417 static const bool forceDownloadFromDownloadAttribute = false;
3418#else
3419 static const bool forceDownloadFromDownloadAttribute = true;
3420#endif
3421 if (policyAction == PolicyAction::Use && navigation && (navigation->isSystemPreview() || (forceDownloadFromDownloadAttribute && navigation->shouldPerformDownload())))
3422 policyAction = PolicyAction::Download;
3423
3424 if (policyAction != PolicyAction::Use || !frame.isMainFrame() || !navigation) {
3425 receivedPolicyDecision(policyAction, navigation, WTFMove(policies), WTFMove(navigationAction), WTFMove(sender));
3426 return;
3427 }
3428
3429 Ref<WebProcessProxy> sourceProcess = process();
3430 URL sourceURL = URL { URL(), pageLoadState().url() };
3431 if (auto* provisionalPage = provisionalPageProxy()) {
3432 if (provisionalPage->navigationID() == navigation->navigationID()) {
3433 sourceProcess = provisionalPage->process();
3434 sourceURL = provisionalPage->provisionalURL();
3435 }
3436 }
3437
3438 process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, WTFMove(websiteDataStore), [this, protectedThis = makeRef(*this), policyAction, navigation = makeRef(*navigation), navigationAction = WTFMove(navigationAction), sourceProcess = sourceProcess.copyRef(),
3439 policies = WTFMove(policies), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
3440 // If the navigation has been destroyed, then no need to proceed.
3441 if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
3442 receivedPolicyDecision(policyAction, navigation.ptr(), WTFMove(policies), WTFMove(navigationAction), WTFMove(sender));
3443 return;
3444 }
3445
3446 bool shouldProcessSwap = processForNavigation.ptr() != sourceProcess.ptr();
3447 if (shouldProcessSwap) {
3448 policyAction = PolicyAction::StopAllLoads;
3449 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "decidePolicyForNavigationAction, swapping process %i with process %i for navigation, reason=%" PUBLIC_LOG_STRING, processIdentifier(), processForNavigation->processIdentifier(), reason.utf8().data());
3450 LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), processForNavigation->processIdentifier(), navigation->navigationID(), navigation->loggingString());
3451 } else
3452 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "decidePolicyForNavigationAction: keep using process %i for navigation, reason=%" PUBLIC_LOG_STRING, processIdentifier(), reason.utf8().data());
3453
3454 std::optional<SandboxExtension::Handle> optionalHandle;
3455 if (shouldProcessSwap) {
3456 // Make sure the process to be used for the navigation does not get shutDown now due to destroying SuspendedPageProxy or ProvisionalPageProxy objects.
3457 auto preventNavigationProcessShutdown = processForNavigation->shutdownPreventingScope();
3458
3459 ASSERT(!destinationSuspendedPage || navigation->targetItem());
3460 auto suspendedPage = destinationSuspendedPage ? backForwardCache().takeSuspendedPage(*navigation->targetItem()) : nullptr;
3461
3462 // It is difficult to get history right if we have several WebPage objects inside a single WebProcess for the same WebPageProxy. As a result, if we make sure to
3463 // clear any SuspendedPageProxy for the current page that are backed by the destination process before we proceed with the navigation. This makes sure the WebPage
3464 // we are about to create in the destination process will be the only one associated with this WebPageProxy.
3465 if (!destinationSuspendedPage)
3466 backForwardCache().removeEntriesForPageAndProcess(*this, processForNavigation);
3467
3468 ASSERT(suspendedPage.get() == destinationSuspendedPage);
3469 if (suspendedPage && suspendedPage->pageIsClosedOrClosing())
3470 suspendedPage = nullptr;
3471
3472 continueNavigationInNewProcess(navigation, WTFMove(suspendedPage), WTFMove(processForNavigation), processSwapRequestedByClient, std::exchange(policies, nullptr));
3473 } else {
3474 auto item = navigation->reloadItem() ? navigation->reloadItem() : navigation->targetItem();
3475 if (policyAction == PolicyAction::Use && item) {
3476 auto fullURL = URL { URL(), item->url() };
3477 if (fullURL.protocolIs("file"_s)) {
3478 SandboxExtension::Handle sandboxExtensionHandle;
3479 maybeInitializeSandboxExtensionHandle(processForNavigation.get(), fullURL, item->resourceDirectoryURL(), sandboxExtensionHandle);
3480 optionalHandle = WTFMove(sandboxExtensionHandle);
3481 }
3482 }
3483 }
3484
3485 receivedPolicyDecision(policyAction, navigation.ptr(), shouldProcessSwap ? nullptr : WTFMove(policies), WTFMove(navigationAction), WTFMove(sender), WTFMove(optionalHandle), shouldProcessSwap ? WillContinueLoadInNewProcess::Yes : WillContinueLoadInNewProcess::No);
3486 });
3487}
3488
3489void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, RefPtr<API::WebsitePolicies>&& websitePolicies, Variant<Ref<API::NavigationResponse>, Ref<API::NavigationAction>>&& navigationActionOrResponse, Ref<PolicyDecisionSender>&& sender, std::optional<SandboxExtension::Handle> sandboxExtensionHandle, WillContinueLoadInNewProcess willContinueLoadInNewProcess)
3490{
3491 if (!hasRunningProcess()) {
3492 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Ignore, 0, std::nullopt, std::nullopt });
3493 return;
3494 }
3495
3496 auto transaction = m_pageLoadState.transaction();
3497
3498 if (action == PolicyAction::Ignore && willContinueLoadInNewProcess == WillContinueLoadInNewProcess::No && navigation && navigation->navigationID() == m_pageLoadState.pendingAPIRequest().navigationID)
3499 m_pageLoadState.clearPendingAPIRequest(transaction);
3500
3501 std::optional<DownloadID> downloadID;
3502 if (action == PolicyAction::Download) {
3503 // Create a download proxy.
3504 auto& download = m_process->processPool().createDownloadProxy(m_websiteDataStore, m_decidePolicyForResponseRequest, this, navigation ? navigation->originatingFrameInfo() : FrameInfoData { });
3505 download.setDidStartCallback([this, weakThis = makeWeakPtr(*this), navigationActionOrResponse = WTFMove(navigationActionOrResponse)] (auto* downloadProxy) {
3506 if (!weakThis || !downloadProxy)
3507 return;
3508 WTF::switchOn(navigationActionOrResponse,
3509 [&] (const Ref<API::NavigationResponse>& response) {
3510 if (!response->downloadAttribute().isNull())
3511 downloadProxy->setSuggestedFilename(response->downloadAttribute());
3512 m_navigationClient->navigationResponseDidBecomeDownload(*this, response.get(), *downloadProxy);
3513 }, [&] (const Ref<API::NavigationAction>& action) {
3514 m_navigationClient->navigationActionDidBecomeDownload(*this, action.get(), *downloadProxy);
3515 }
3516 );
3517 });
3518 if (navigation) {
3519 download.setWasUserInitiated(navigation->wasUserInitiated());
3520 download.setRedirectChain(navigation->takeRedirectChain());
3521 }
3522
3523 downloadID = download.downloadID();
3524 handleDownloadRequest(download);
3525 m_decidePolicyForResponseRequest = { };
3526 }
3527
3528 std::optional<WebsitePoliciesData> websitePoliciesData;
3529 if (websitePolicies)
3530 websitePoliciesData = websitePolicies->data();
3531
3532 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePoliciesData), WTFMove(sandboxExtensionHandle) });
3533}
3534
3535void WebPageProxy::commitProvisionalPage(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, WebCore::FrameLoadType frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool usedLegacyTLS, bool containsPluginDocument, std::optional<WebCore::HasInsecureContent> forcedHasInsecureContent, WebCore::MouseEventPolicy mouseEventPolicy, const UserData& userData)
3536{
3537 ASSERT(m_provisionalPage);
3538 WEBPAGEPROXY_RELEASE_LOG(Loading, "commitProvisionalPage: newPID=%i", m_provisionalPage->process().processIdentifier());
3539
3540 std::optional<FrameIdentifier> mainFrameIDInPreviousProcess = m_mainFrame ? std::make_optional(m_mainFrame->frameID()) : std::nullopt;
3541
3542 ASSERT(m_process.ptr() != &m_provisionalPage->process());
3543
3544 auto shouldDelayClosingUntilFirstLayerFlush = ShouldDelayClosingUntilFirstLayerFlush::No;
3545#if PLATFORM(MAC)
3546 // On macOS, when not using UI-side compositing, we need to make sure we do not close the page in the previous process until we've
3547 // entered accelerated compositing for the new page or we will flash on navigation.
3548 if (drawingArea()->type() == DrawingAreaTypeTiledCoreAnimation)
3549 shouldDelayClosingUntilFirstLayerFlush = ShouldDelayClosingUntilFirstLayerFlush::Yes;
3550#endif
3551
3552 if (m_isLayerTreeFrozenDueToSwipeAnimation)
3553 send(Messages::WebPage::UnfreezeLayerTreeDueToSwipeAnimation());
3554
3555 resetStateAfterProcessTermination(ProcessTerminationReason::NavigationSwap);
3556
3557 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
3558 auto* navigation = navigationState().navigation(m_provisionalPage->navigationID());
3559 bool didSuspendPreviousPage = navigation ? suspendCurrentPageIfPossible(*navigation, mainFrameIDInPreviousProcess, m_provisionalPage->processSwapRequestedByClient(), shouldDelayClosingUntilFirstLayerFlush) : false;
3560 m_process->removeWebPage(*this, m_websiteDataStore.ptr() == &m_provisionalPage->process().websiteDataStore() ? WebProcessProxy::EndsUsingDataStore::No : WebProcessProxy::EndsUsingDataStore::Yes);
3561
3562 // There is no way we'll be able to return to the page in the previous page so close it.
3563 if (!didSuspendPreviousPage)
3564 send(Messages::WebPage::Close());
3565
3566 const auto oldWebPageID = m_webPageID;
3567 swapToProvisionalPage(std::exchange(m_provisionalPage, nullptr));
3568
3569 didCommitLoadForFrame(frameID, WTFMove(frameInfo), WTFMove(request), navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, usedLegacyTLS, containsPluginDocument, forcedHasInsecureContent, mouseEventPolicy, userData);
3570
3571 m_inspectorController->didCommitProvisionalPage(oldWebPageID, m_webPageID);
3572}
3573
3574void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPage, Ref<WebProcessProxy>&& newProcess, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<API::WebsitePolicies>&& websitePolicies)
3575{
3576 WEBPAGEPROXY_RELEASE_LOG(Loading, "continueNavigationInNewProcess: newProcessPID=%i, hasSuspendedPage=%i", newProcess->processIdentifier(), !!suspendedPage);
3577 LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString());
3578 RELEASE_ASSERT(!newProcess->isInProcessCache());
3579
3580 if (m_provisionalPage) {
3581 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "continueNavigationInNewProcess: There is already a pending provisional load, cancelling it (provisonalNavigationID=%llu, navigationID=%llu)", m_provisionalPage->navigationID(), navigation.navigationID());
3582 if (m_provisionalPage->navigationID() != navigation.navigationID())
3583 m_provisionalPage->cancel();
3584 m_provisionalPage = nullptr;
3585 }
3586
3587 m_provisionalPage = makeUnique<ProvisionalPageProxy>(*this, WTFMove(newProcess), WTFMove(suspendedPage), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient, websitePolicies.get());
3588
3589 auto continuation = [this, protectedThis = makeRef(*this), navigation = makeRef(navigation), websitePolicies = WTFMove(websitePolicies)]() mutable {
3590 if (auto* item = navigation->targetItem()) {
3591 LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
3592
3593 auto transaction = m_pageLoadState.transaction();
3594 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), item->url() });
3595
3596 m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
3597 return;
3598 }
3599
3600 if (m_backForwardList->currentItem() && (navigation->lockBackForwardList() == LockBackForwardList::Yes || navigation->lockHistory() == LockHistory::Yes)) {
3601 // If WebCore is supposed to lock the history for this load, then the new process needs to know about the current history item so it can update
3602 // it instead of creating a new one.
3603 m_provisionalPage->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()));
3604 }
3605
3606 std::optional<WebsitePoliciesData> websitePoliciesData;
3607 if (websitePolicies)
3608 websitePoliciesData = websitePolicies->data();
3609
3610 // FIXME: Work out timing of responding with the last policy delegate, etc
3611 ASSERT(!navigation->currentRequest().isEmpty());
3612 if (auto& substituteData = navigation->substituteData())
3613 m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), isNavigatingToAppBoundDomain(), WTFMove(websitePoliciesData));
3614 else
3615 m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation->currentRequest() }, nullptr, isNavigatingToAppBoundDomain(), WTFMove(websitePoliciesData));
3616 };
3617 if (m_inspectorController->shouldPauseLoading(*m_provisionalPage))
3618 m_inspectorController->setContinueLoadingCallback(*m_provisionalPage, WTFMove(continuation));
3619 else
3620 continuation();
3621}
3622
3623bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const
3624{
3625 return openedByDOM() && !hasCommittedAnyProvisionalLoads();
3626}
3627
3628// MSVC gives a redeclaration error if noreturn is used on the definition and not the declaration, while
3629// Cocoa tests segfault if it is moved to the declaration site (even if we move the definition with it!).
3630#if !COMPILER(MSVC)
3631NO_RETURN_DUE_TO_ASSERT
3632#endif
3633void WebPageProxy::didFailToSuspendAfterProcessSwap()
3634{
3635 // Only the SuspendedPageProxy should be getting this call.
3636 ASSERT_NOT_REACHED();
3637}
3638
3639#if !COMPILER(MSVC)
3640NO_RETURN_DUE_TO_ASSERT
3641#endif
3642void WebPageProxy::didSuspendAfterProcessSwap()
3643{
3644 // Only the SuspendedPageProxy should be getting this call.
3645 ASSERT_NOT_REACHED();
3646}
3647
3648void WebPageProxy::setUserAgent(String&& userAgent)
3649{
3650 if (m_userAgent == userAgent)
3651 return;
3652 m_userAgent = WTFMove(userAgent);
3653
3654#if ENABLE(SERVICE_WORKER)
3655 // We update the service worker there at the moment to be sure we use values used by actual web pages.
3656 // FIXME: Refactor this when we have a better User-Agent story.
3657 process().processPool().updateServiceWorkerUserAgent(m_userAgent);
3658#endif
3659
3660 if (!hasRunningProcess())
3661 return;
3662 send(Messages::WebPage::SetUserAgent(m_userAgent));
3663}
3664
3665void WebPageProxy::setApplicationNameForUserAgent(const String& applicationName)
3666{
3667 if (m_applicationNameForUserAgent == applicationName)
3668 return;
3669
3670 m_applicationNameForUserAgent = applicationName;
3671 if (!m_customUserAgent.isEmpty())
3672 return;
3673
3674 setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3675}
3676
3677void WebPageProxy::setCustomUserAgent(const String& customUserAgent)
3678{
3679 if (m_customUserAgent == customUserAgent)
3680 return;
3681
3682 m_customUserAgent = customUserAgent;
3683
3684 if (m_customUserAgent.isEmpty()) {
3685 setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3686 return;
3687 }
3688
3689 setUserAgent(String { m_customUserAgent });
3690}
3691
3692void WebPageProxy::resumeActiveDOMObjectsAndAnimations()
3693{
3694 if (!hasRunningProcess() || !m_areActiveDOMObjectsAndAnimationsSuspended)
3695 return;
3696
3697 m_areActiveDOMObjectsAndAnimationsSuspended = false;
3698
3699 send(Messages::WebPage::ResumeActiveDOMObjectsAndAnimations());
3700}
3701
3702void WebPageProxy::suspendActiveDOMObjectsAndAnimations()
3703{
3704 if (!hasRunningProcess() || m_areActiveDOMObjectsAndAnimationsSuspended)
3705 return;
3706
3707 m_areActiveDOMObjectsAndAnimationsSuspended = true;
3708
3709 send(Messages::WebPage::SuspendActiveDOMObjectsAndAnimations());
3710}
3711
3712void WebPageProxy::suspend(CompletionHandler<void(bool)>&& completionHandler)
3713{
3714 WEBPAGEPROXY_RELEASE_LOG(Loading, "suspend:");
3715 if (!hasRunningProcess() || m_isSuspended)
3716 return completionHandler(false);
3717
3718 m_isSuspended = true;
3719 sendWithAsyncReply(Messages::WebPage::Suspend(), WTFMove(completionHandler));
3720}
3721
3722void WebPageProxy::resume(CompletionHandler<void(bool)>&& completionHandler)
3723{
3724 WEBPAGEPROXY_RELEASE_LOG(Loading, "resume:");
3725
3726 if (!hasRunningProcess() || !m_isSuspended)
3727 return completionHandler(false);
3728
3729 m_isSuspended = false;
3730 sendWithAsyncReply(Messages::WebPage::Resume(), WTFMove(completionHandler));
3731}
3732
3733bool WebPageProxy::supportsTextEncoding() const
3734{
3735 // FIXME (118840): We should probably only support this for text documents, not all non-image documents.
3736 return m_mainFrame && !m_mainFrame->isDisplayingStandaloneImageDocument();
3737}
3738
3739void WebPageProxy::setCustomTextEncodingName(const String& encodingName)
3740{
3741 if (m_customTextEncodingName == encodingName)
3742 return;
3743 m_customTextEncodingName = encodingName;
3744
3745 if (!hasRunningProcess())
3746 return;
3747 send(Messages::WebPage::SetCustomTextEncodingName(encodingName));
3748}
3749
3750SessionState WebPageProxy::sessionState(WTF::Function<bool (WebBackForwardListItem&)>&& filter) const
3751{
3752 RELEASE_ASSERT(RunLoop::isMain());
3753 SessionState sessionState;
3754
3755 sessionState.backForwardListState = m_backForwardList->backForwardListState(WTFMove(filter));
3756
3757 String provisionalURLString = m_pageLoadState.pendingAPIRequestURL();
3758 if (provisionalURLString.isEmpty())
3759 provisionalURLString = m_pageLoadState.provisionalURL();
3760
3761 if (!provisionalURLString.isEmpty())
3762 sessionState.provisionalURL = URL(URL(), provisionalURLString);
3763
3764 sessionState.renderTreeSize = renderTreeSize();
3765 return sessionState;
3766}
3767
3768RefPtr<API::Navigation> WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate)
3769{
3770 WEBPAGEPROXY_RELEASE_LOG(Loading, "restoreFromSessionState:");
3771
3772 m_sessionRestorationRenderTreeSize = 0;
3773 m_hitRenderTreeSizeThreshold = false;
3774
3775 bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex;
3776
3777 if (hasBackForwardList) {
3778 m_sessionStateWasRestoredByAPIRequest = true;
3779
3780 m_backForwardList->restoreFromState(WTFMove(sessionState.backForwardListState));
3781 // If the process is not launched yet, the session will be restored when sending the WebPageCreationParameters;
3782 if (hasRunningProcess())
3783 send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()));
3784
3785 auto transaction = m_pageLoadState.transaction();
3786 m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
3787 m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
3788
3789 // The back / forward list was restored from a sessionState so we don't want to snapshot the current
3790 // page when navigating away. Suppress navigation snapshotting until the next load has committed
3791 suppressNextAutomaticNavigationSnapshot();
3792 }
3793
3794 // FIXME: Navigating should be separate from state restoration.
3795 if (navigate) {
3796 m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize;
3797 if (!m_sessionRestorationRenderTreeSize)
3798 m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone.
3799
3800 if (!sessionState.provisionalURL.isNull())
3801 return loadRequest(sessionState.provisionalURL);
3802
3803 if (hasBackForwardList) {
3804 if (WebBackForwardListItem* item = m_backForwardList->currentItem())
3805 return goToBackForwardItem(*item);
3806 }
3807 }
3808
3809 return nullptr;
3810}
3811
3812bool WebPageProxy::supportsTextZoom() const
3813{
3814 // FIXME (118840): This should also return false for standalone media and plug-in documents.
3815 if (!m_mainFrame || m_mainFrame->isDisplayingStandaloneImageDocument())
3816 return false;
3817
3818 return true;
3819}
3820
3821void WebPageProxy::setTextZoomFactor(double zoomFactor)
3822{
3823 if (m_textZoomFactor == zoomFactor)
3824 return;
3825
3826 m_textZoomFactor = zoomFactor;
3827
3828 if (!hasRunningProcess())
3829 return;
3830
3831 send(Messages::WebPage::SetTextZoomFactor(m_textZoomFactor));
3832}
3833
3834void WebPageProxy::setPageZoomFactor(double zoomFactor)
3835{
3836 if (m_pageZoomFactor == zoomFactor)
3837 return;
3838
3839 closeOverlayedViews();
3840
3841 m_pageZoomFactor = zoomFactor;
3842
3843 if (!hasRunningProcess())
3844 return;
3845
3846 send(Messages::WebPage::SetPageZoomFactor(m_pageZoomFactor));
3847}
3848
3849void WebPageProxy::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
3850{
3851 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
3852 return;
3853
3854 closeOverlayedViews();
3855
3856 m_pageZoomFactor = pageZoomFactor;
3857 m_textZoomFactor = textZoomFactor;
3858
3859 if (!hasRunningProcess())
3860 return;
3861
3862 send(Messages::WebPage::SetPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor));
3863}
3864
3865double WebPageProxy::pageZoomFactor() const
3866{
3867 // Zoom factor for non-PDF pages persists across page loads. We maintain a separate member variable for PDF
3868 // zoom which ensures that we don't use the PDF zoom for a normal page.
3869 if (m_mainFramePluginHandlesPageScaleGesture)
3870 return m_pluginZoomFactor;
3871 return m_pageZoomFactor;
3872}
3873
3874double WebPageProxy::pageScaleFactor() const
3875{
3876 // PDF documents use zoom and scale factors to size themselves appropriately in the window. We store them
3877 // separately but decide which to return based on the main frame.
3878 if (m_mainFramePluginHandlesPageScaleGesture)
3879 return m_pluginScaleFactor;
3880 return m_pageScaleFactor;
3881}
3882
3883void WebPageProxy::scalePage(double scale, const IntPoint& origin)
3884{
3885 ASSERT(scale > 0);
3886
3887 m_pageScaleFactor = scale;
3888
3889 if (!hasRunningProcess())
3890 return;
3891
3892 send(Messages::WebPage::ScalePage(scale, origin));
3893}
3894
3895void WebPageProxy::scalePageInViewCoordinates(double scale, const IntPoint& centerInViewCoordinates)
3896{
3897 ASSERT(scale > 0);
3898
3899 m_pageScaleFactor = scale;
3900
3901 if (!hasRunningProcess())
3902 return;
3903
3904 send(Messages::WebPage::ScalePageInViewCoordinates(scale, centerInViewCoordinates));
3905}
3906
3907void WebPageProxy::scaleView(double scale)
3908{
3909 ASSERT(scale > 0);
3910
3911 m_viewScaleFactor = scale;
3912
3913 if (!hasRunningProcess())
3914 return;
3915
3916 send(Messages::WebPage::ScaleView(scale));
3917}
3918
3919void WebPageProxy::setIntrinsicDeviceScaleFactor(float scaleFactor)
3920{
3921 if (m_intrinsicDeviceScaleFactor == scaleFactor)
3922 return;
3923
3924 m_intrinsicDeviceScaleFactor = scaleFactor;
3925
3926 if (m_drawingArea)
3927 m_drawingArea->deviceScaleFactorDidChange();
3928}
3929
3930void WebPageProxy::windowScreenDidChange(PlatformDisplayID displayID, std::optional<unsigned> nominalFramesPerSecond)
3931{
3932 m_displayID = displayID;
3933
3934 if (m_wheelEventCoalescer)
3935 m_wheelEventCoalescer->setShouldCoalesceEventsDuringDeceleration(shouldCoalesceWheelEventsDuringDeceleration());
3936
3937 if (!hasRunningProcess())
3938 return;
3939
3940 send(Messages::WebPage::WindowScreenDidChange(displayID, nominalFramesPerSecond));
3941}
3942
3943float WebPageProxy::deviceScaleFactor() const
3944{
3945 return m_customDeviceScaleFactor.value_or(m_intrinsicDeviceScaleFactor);
3946}
3947
3948void WebPageProxy::setCustomDeviceScaleFactor(float customScaleFactor)
3949{
3950 if (m_customDeviceScaleFactor && m_customDeviceScaleFactor.value() == customScaleFactor)
3951 return;
3952
3953 float oldScaleFactor = deviceScaleFactor();
3954
3955 // A value of 0 clears the customScaleFactor.
3956 if (customScaleFactor)
3957 m_customDeviceScaleFactor = customScaleFactor;
3958 else
3959 m_customDeviceScaleFactor = std::nullopt;
3960
3961 if (!hasRunningProcess())
3962 return;
3963
3964 if (deviceScaleFactor() != oldScaleFactor)
3965 m_drawingArea->deviceScaleFactorDidChange();
3966}
3967
3968void WebPageProxy::accessibilitySettingsDidChange()
3969{
3970 if (!hasRunningProcess())
3971 return;
3972
3973 // Also update screen properties which encodes invert colors.
3974 process().processPool().screenPropertiesStateChanged();
3975 send(Messages::WebPage::AccessibilitySettingsDidChange());
3976}
3977
3978void WebPageProxy::setUseFixedLayout(bool fixed)
3979{
3980 // This check is fine as the value is initialized in the web
3981 // process as part of the creation parameters.
3982 if (fixed == m_useFixedLayout)
3983 return;
3984
3985 m_useFixedLayout = fixed;
3986 if (!fixed)
3987 m_fixedLayoutSize = IntSize();
3988
3989 if (!hasRunningProcess())
3990 return;
3991
3992 send(Messages::WebPage::SetUseFixedLayout(fixed));
3993}
3994
3995void WebPageProxy::setFixedLayoutSize(const IntSize& size)
3996{
3997 if (size == m_fixedLayoutSize)
3998 return;
3999
4000 m_fixedLayoutSize = size;
4001
4002 if (!hasRunningProcess())
4003 return;
4004
4005 send(Messages::WebPage::SetFixedLayoutSize(size));
4006}
4007
4008void WebPageProxy::setViewExposedRect(std::optional<WebCore::FloatRect> viewExposedRect)
4009{
4010 if (m_viewExposedRect == viewExposedRect)
4011 return;
4012
4013 m_viewExposedRect = viewExposedRect;
4014
4015#if PLATFORM(MAC)
4016 if (m_drawingArea)
4017 m_drawingArea->didChangeViewExposedRect();
4018#endif
4019}
4020
4021void WebPageProxy::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
4022{
4023 if (alwaysShowsHorizontalScroller == m_alwaysShowsHorizontalScroller)
4024 return;
4025
4026 m_alwaysShowsHorizontalScroller = alwaysShowsHorizontalScroller;
4027
4028 if (!hasRunningProcess())
4029 return;
4030
4031 send(Messages::WebPage::SetAlwaysShowsHorizontalScroller(alwaysShowsHorizontalScroller));
4032}
4033
4034void WebPageProxy::setAlwaysShowsVerticalScroller(bool alwaysShowsVerticalScroller)
4035{
4036 if (alwaysShowsVerticalScroller == m_alwaysShowsVerticalScroller)
4037 return;
4038
4039 m_alwaysShowsVerticalScroller = alwaysShowsVerticalScroller;
4040
4041 if (!hasRunningProcess())
4042 return;
4043
4044 send(Messages::WebPage::SetAlwaysShowsVerticalScroller(alwaysShowsVerticalScroller));
4045}
4046
4047void WebPageProxy::listenForLayoutMilestones(OptionSet<WebCore::LayoutMilestone> milestones)
4048{
4049 if (milestones == m_observedLayoutMilestones)
4050 return;
4051
4052 m_observedLayoutMilestones = milestones;
4053
4054 if (!hasRunningProcess())
4055 return;
4056
4057 send(Messages::WebPage::ListenForLayoutMilestones(milestones));
4058}
4059
4060void WebPageProxy::setSuppressScrollbarAnimations(bool suppressAnimations)
4061{
4062 if (suppressAnimations == m_suppressScrollbarAnimations)
4063 return;
4064
4065 m_suppressScrollbarAnimations = suppressAnimations;
4066
4067 if (!hasRunningProcess())
4068 return;
4069
4070 send(Messages::WebPage::SetSuppressScrollbarAnimations(suppressAnimations));
4071}
4072
4073bool WebPageProxy::rubberBandsAtLeft() const
4074{
4075 return m_rubberBandsAtLeft;
4076}
4077
4078void WebPageProxy::setRubberBandsAtLeft(bool rubberBandsAtLeft)
4079{
4080 m_rubberBandsAtLeft = rubberBandsAtLeft;
4081}
4082
4083bool WebPageProxy::rubberBandsAtRight() const
4084{
4085 return m_rubberBandsAtRight;
4086}
4087
4088void WebPageProxy::setRubberBandsAtRight(bool rubberBandsAtRight)
4089{
4090 m_rubberBandsAtRight = rubberBandsAtRight;
4091}
4092
4093bool WebPageProxy::rubberBandsAtTop() const
4094{
4095 return m_rubberBandsAtTop;
4096}
4097
4098void WebPageProxy::setRubberBandsAtTop(bool rubberBandsAtTop)
4099{
4100 m_rubberBandsAtTop = rubberBandsAtTop;
4101}
4102
4103bool WebPageProxy::rubberBandsAtBottom() const
4104{
4105 return m_rubberBandsAtBottom;
4106}
4107
4108void WebPageProxy::setRubberBandsAtBottom(bool rubberBandsAtBottom)
4109{
4110 m_rubberBandsAtBottom = rubberBandsAtBottom;
4111}
4112
4113void WebPageProxy::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding)
4114{
4115 if (enableVerticalRubberBanding == m_enableVerticalRubberBanding)
4116 return;
4117
4118 m_enableVerticalRubberBanding = enableVerticalRubberBanding;
4119
4120 if (!hasRunningProcess())
4121 return;
4122 send(Messages::WebPage::SetEnableVerticalRubberBanding(enableVerticalRubberBanding));
4123}
4124
4125bool WebPageProxy::verticalRubberBandingIsEnabled() const
4126{
4127 return m_enableVerticalRubberBanding;
4128}
4129
4130void WebPageProxy::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding)
4131{
4132 if (enableHorizontalRubberBanding == m_enableHorizontalRubberBanding)
4133 return;
4134
4135 m_enableHorizontalRubberBanding = enableHorizontalRubberBanding;
4136
4137 if (!hasRunningProcess())
4138 return;
4139 send(Messages::WebPage::SetEnableHorizontalRubberBanding(enableHorizontalRubberBanding));
4140}
4141
4142bool WebPageProxy::horizontalRubberBandingIsEnabled() const
4143{
4144 return m_enableHorizontalRubberBanding;
4145}
4146
4147void WebPageProxy::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage)
4148{
4149 if (backgroundExtendsBeyondPage == m_backgroundExtendsBeyondPage)
4150 return;
4151
4152 m_backgroundExtendsBeyondPage = backgroundExtendsBeyondPage;
4153
4154 if (!hasRunningProcess())
4155 return;
4156 send(Messages::WebPage::SetBackgroundExtendsBeyondPage(backgroundExtendsBeyondPage));
4157}
4158
4159bool WebPageProxy::backgroundExtendsBeyondPage() const
4160{
4161 return m_backgroundExtendsBeyondPage;
4162}
4163
4164void WebPageProxy::setPaginationMode(WebCore::Pagination::Mode mode)
4165{
4166 if (mode == m_paginationMode)
4167 return;
4168
4169 m_paginationMode = mode;
4170
4171 if (!hasRunningProcess())
4172 return;
4173 send(Messages::WebPage::SetPaginationMode(mode));
4174}
4175
4176void WebPageProxy::setPaginationBehavesLikeColumns(bool behavesLikeColumns)
4177{
4178 if (behavesLikeColumns == m_paginationBehavesLikeColumns)
4179 return;
4180
4181 m_paginationBehavesLikeColumns = behavesLikeColumns;
4182
4183 if (!hasRunningProcess())
4184 return;
4185 send(Messages::WebPage::SetPaginationBehavesLikeColumns(behavesLikeColumns));
4186}
4187
4188void WebPageProxy::setPageLength(double pageLength)
4189{
4190 if (pageLength == m_pageLength)
4191 return;
4192
4193 m_pageLength = pageLength;
4194
4195 if (!hasRunningProcess())
4196 return;
4197 send(Messages::WebPage::SetPageLength(pageLength));
4198}
4199
4200void WebPageProxy::setGapBetweenPages(double gap)
4201{
4202 if (gap == m_gapBetweenPages)
4203 return;
4204
4205 m_gapBetweenPages = gap;
4206
4207 if (!hasRunningProcess())
4208 return;
4209 send(Messages::WebPage::SetGapBetweenPages(gap));
4210}
4211
4212void WebPageProxy::setPaginationLineGridEnabled(bool lineGridEnabled)
4213{
4214 if (lineGridEnabled == m_paginationLineGridEnabled)
4215 return;
4216
4217 m_paginationLineGridEnabled = lineGridEnabled;
4218
4219 if (!hasRunningProcess())
4220 return;
4221 send(Messages::WebPage::SetPaginationLineGridEnabled(lineGridEnabled));
4222}
4223
4224void WebPageProxy::pageScaleFactorDidChange(double scaleFactor)
4225{
4226 m_pageScaleFactor = scaleFactor;
4227}
4228
4229void WebPageProxy::pluginScaleFactorDidChange(double pluginScaleFactor)
4230{
4231 m_pluginScaleFactor = pluginScaleFactor;
4232}
4233
4234void WebPageProxy::pluginZoomFactorDidChange(double pluginZoomFactor)
4235{
4236 m_pluginZoomFactor = pluginZoomFactor;
4237}
4238
4239void WebPageProxy::findStringMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount)
4240{
4241 if (string.isEmpty()) {
4242 didFindStringMatches(string, Vector<Vector<WebCore::IntRect>> (), 0);
4243 return;
4244 }
4245
4246 send(Messages::WebPage::FindStringMatches(string, options, maxMatchCount));
4247}
4248
4249void WebPageProxy::findString(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(bool)>&& callbackFunction)
4250{
4251 sendWithAsyncReply(Messages::WebPage::FindString(string, options, maxMatchCount), WTFMove(callbackFunction));
4252}
4253
4254void WebPageProxy::getImageForFindMatch(int32_t matchIndex)
4255{
4256 send(Messages::WebPage::GetImageForFindMatch(matchIndex));
4257}
4258
4259void WebPageProxy::selectFindMatch(int32_t matchIndex)
4260{
4261 send(Messages::WebPage::SelectFindMatch(matchIndex));
4262}
4263
4264void WebPageProxy::indicateFindMatch(int32_t matchIndex)
4265{
4266 send(Messages::WebPage::IndicateFindMatch(matchIndex));
4267}
4268
4269void WebPageProxy::hideFindUI()
4270{
4271 send(Messages::WebPage::HideFindUI());
4272}
4273
4274void WebPageProxy::countStringMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount)
4275{
4276 if (!hasRunningProcess())
4277 return;
4278
4279 send(Messages::WebPage::CountStringMatches(string, options, maxMatchCount));
4280}
4281
4282void WebPageProxy::replaceMatches(Vector<uint32_t>&& matchIndices, const String& replacementText, bool selectionOnly, CompletionHandler<void(uint64_t)>&& callback)
4283{
4284 sendWithAsyncReply(Messages::WebPage::ReplaceMatches(WTFMove(matchIndices), replacementText, selectionOnly), WTFMove(callback));
4285}
4286
4287void WebPageProxy::launchInitialProcessIfNecessary()
4288{
4289 if (process().isDummyProcessProxy())
4290 launchProcess({ }, ProcessLaunchReason::InitialProcess);
4291}
4292
4293void WebPageProxy::runJavaScriptInMainFrame(RunJavaScriptParameters&& parameters, CompletionHandler<void(Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails>&&)>&& callbackFunction)
4294{
4295 runJavaScriptInFrameInScriptWorld(WTFMove(parameters), std::nullopt, API::ContentWorld::pageContentWorld(), WTFMove(callbackFunction));
4296}
4297
4298void WebPageProxy::runJavaScriptInFrameInScriptWorld(RunJavaScriptParameters&& parameters, std::optional<WebCore::FrameIdentifier> frameID, API::ContentWorld& world, CompletionHandler<void(Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails>&&)>&& callbackFunction)
4299{
4300 // For backward-compatibility support running script in a WebView which has not done any loads yets.
4301 launchInitialProcessIfNecessary();
4302
4303 if (!hasRunningProcess())
4304 return callbackFunction({ nullptr });
4305
4306 ProcessThrottler::ActivityVariant activity;
4307#if PLATFORM(IOS_FAMILY)
4308 if (pageClient().canTakeForegroundAssertions())
4309 activity = m_process->throttler().foregroundActivity("WebPageProxy::runJavaScriptInFrameInScriptWorld"_s);
4310#endif
4311
4312 sendWithAsyncReply(Messages::WebPage::RunJavaScriptInFrameInScriptWorld(parameters, frameID, world.worldData()), [activity = WTFMove(activity), callbackFunction = WTFMove(callbackFunction)] (const IPC::DataReference& dataReference, std::optional<ExceptionDetails>&& details) mutable {
4313 if (details)
4314 return callbackFunction(makeUnexpected(WTFMove(*details)));
4315 if (dataReference.isEmpty())
4316 return callbackFunction({ nullptr });
4317 Vector<uint8_t> data;
4318 data.reserveInitialCapacity(dataReference.size());
4319 data.append(dataReference.data(), dataReference.size());
4320 callbackFunction({ API::SerializedScriptValue::adopt(WTFMove(data)).ptr() });
4321 });
4322}
4323
4324void WebPageProxy::getRenderTreeExternalRepresentation(CompletionHandler<void(const String&)>&& callback)
4325{
4326 sendWithAsyncReply(Messages::WebPage::GetRenderTreeExternalRepresentation(), WTFMove(callback));
4327}
4328
4329void WebPageProxy::getSourceForFrame(WebFrameProxy* frame, CompletionHandler<void(const String&)>&& callback)
4330{
4331 sendWithAsyncReply(Messages::WebPage::GetSourceForFrame(frame->frameID()), WTFMove(callback));
4332}
4333
4334void WebPageProxy::getContentsAsString(ContentAsStringIncludesChildFrames includesChildFrames, CompletionHandler<void(const String&)>&& callback)
4335{
4336 sendWithAsyncReply(Messages::WebPage::GetContentsAsString(includesChildFrames), WTFMove(callback));
4337}
4338
4339#if PLATFORM(COCOA)
4340void WebPageProxy::getContentsAsAttributedString(CompletionHandler<void(const WebCore::AttributedString&)>&& completionHandler)
4341{
4342 if (!hasRunningProcess()) {
4343 completionHandler({ });
4344 return;
4345 }
4346
4347 sendWithAsyncReply(Messages::WebPage::GetContentsAsAttributedString(), WTFMove(completionHandler));
4348}
4349#endif
4350
4351void WebPageProxy::getAllFrames(CompletionHandler<void(FrameTreeNodeData&&)>&& completionHandler)
4352{
4353 sendWithAsyncReply(Messages::WebPage::GetAllFrames(), WTFMove(completionHandler));
4354}
4355
4356void WebPageProxy::getBytecodeProfile(CompletionHandler<void(const String&)>&& callback)
4357{
4358 sendWithAsyncReply(Messages::WebPage::GetBytecodeProfile(), WTFMove(callback));
4359}
4360
4361void WebPageProxy::getSamplingProfilerOutput(CompletionHandler<void(const String&)>&& callback)
4362{
4363 sendWithAsyncReply(Messages::WebPage::GetSamplingProfilerOutput(), WTFMove(callback));
4364}
4365
4366static CompletionHandler<void(const std::optional<IPC::DataReference>& data)> toAPIDataCallback(CompletionHandler<void(API::Data*)>&& callback)
4367{
4368 return [callback = WTFMove(callback)] (const std::optional<IPC::DataReference>& data) mutable {
4369 callback(data ? API::Data::create(data->data(), data->size()).ptr() : nullptr);
4370 };
4371}
4372
4373#if ENABLE(MHTML)
4374void WebPageProxy::getContentsAsMHTMLData(CompletionHandler<void(API::Data*)>&& callback)
4375{
4376 sendWithAsyncReply(Messages::WebPage::GetContentsAsMHTMLData(), toAPIDataCallback(WTFMove(callback)));
4377}
4378#endif
4379
4380void WebPageProxy::getSelectionOrContentsAsString(CompletionHandler<void(const String&)>&& callback)
4381{
4382 sendWithAsyncReply(Messages::WebPage::GetSelectionOrContentsAsString(), callback);
4383}
4384
4385void WebPageProxy::getSelectionAsWebArchiveData(CompletionHandler<void(API::Data*)>&& callback)
4386{
4387 sendWithAsyncReply(Messages::WebPage::GetSelectionAsWebArchiveData(), toAPIDataCallback(WTFMove(callback)));
4388}
4389
4390void WebPageProxy::getMainResourceDataOfFrame(WebFrameProxy* frame, CompletionHandler<void(API::Data*)>&& callback)
4391{
4392 if (!frame)
4393 return callback(nullptr);
4394 sendWithAsyncReply(Messages::WebPage::GetMainResourceDataOfFrame(frame->frameID()), toAPIDataCallback(WTFMove(callback)));
4395}
4396
4397void WebPageProxy::getResourceDataFromFrame(WebFrameProxy& frame, API::URL* resourceURL, CompletionHandler<void(API::Data*)>&& callback)
4398{
4399 sendWithAsyncReply(Messages::WebPage::GetResourceDataFromFrame(frame.frameID(), resourceURL->string()), toAPIDataCallback(WTFMove(callback)));
4400}
4401
4402void WebPageProxy::getWebArchiveOfFrame(WebFrameProxy* frame, CompletionHandler<void(API::Data*)>&& callback)
4403{
4404 if (!frame)
4405 return callback(nullptr);
4406 sendWithAsyncReply(Messages::WebPage::GetWebArchiveOfFrame(frame->frameID()), toAPIDataCallback(WTFMove(callback)));
4407}
4408
4409void WebPageProxy::forceRepaint(CompletionHandler<void()>&& callback)
4410{
4411 if (!hasRunningProcess())
4412 return callback();
4413
4414 m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
4415
4416 sendWithAsyncReply(Messages::WebPage::ForceRepaint(), [this, protectedThis = makeRef(*this), callback = WTFMove(callback)] () mutable {
4417 callAfterNextPresentationUpdate([callback = WTFMove(callback)] (auto) mutable {
4418 callback();
4419 });
4420 });
4421}
4422
4423static OptionSet<IPC::SendOption> printingSendOptions(bool isPerformingDOMPrintOperation)
4424{
4425 if (isPerformingDOMPrintOperation)
4426 return IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply;
4427
4428 return { };
4429}
4430
4431void WebPageProxy::preferencesDidChange()
4432{
4433 if (!hasRunningProcess())
4434 return;
4435
4436 updateThrottleState();
4437 updateHiddenPageThrottlingAutoIncreases();
4438
4439 pageClient().preferencesDidChange();
4440
4441 // FIXME: It probably makes more sense to send individual preference changes.
4442 // However, WebKitTestRunner depends on getting a preference change notification
4443 // even if nothing changed in UI process, so that overrides get removed.
4444
4445 // Preferences need to be updated during synchronous printing to make "print backgrounds" preference work when toggled from a print dialog checkbox.
4446 send(Messages::WebPage::PreferencesDidChange(preferencesStore()), printingSendOptions(m_isPerformingDOMPrintOperation));
4447}
4448
4449void WebPageProxy::didCreateMainFrame(FrameIdentifier frameID)
4450{
4451 // The DecidePolicyForNavigationActionSync IPC is synchronous and may therefore get processed before the DidCreateMainFrame one.
4452 // When this happens, decidePolicyForNavigationActionSync() calls didCreateMainFrame() and we need to ignore the DidCreateMainFrame
4453 // IPC when it later gets processed.
4454 if (m_mainFrame && m_mainFrame->frameID() == frameID)
4455 return;
4456
4457 PageClientProtector protector(pageClient());
4458
4459 MESSAGE_CHECK(m_process, !m_mainFrame);
4460 MESSAGE_CHECK(m_process, m_process->canCreateFrame(frameID));
4461
4462 m_mainFrame = WebFrameProxy::create(*this, frameID);
4463
4464 // Add the frame to the process wide map.
4465 m_process->frameCreated(frameID, *m_mainFrame);
4466}
4467
4468void WebPageProxy::didCreateSubframe(FrameIdentifier frameID)
4469{
4470 PageClientProtector protector(pageClient());
4471
4472 MESSAGE_CHECK(m_process, m_mainFrame);
4473
4474 // The DecidePolicyForNavigationActionSync IPC is synchronous and may therefore get processed before the DidCreateSubframe one.
4475 // When this happens, decidePolicyForNavigationActionSync() calls didCreateSubframe() and we need to ignore the DidCreateSubframe
4476 // IPC when it later gets processed.
4477 if (m_process->webFrame(frameID))
4478 return;
4479
4480 MESSAGE_CHECK(m_process, m_process->canCreateFrame(frameID));
4481
4482 auto subFrame = WebFrameProxy::create(*this, frameID);
4483
4484 // Add the frame to the process wide map.
4485 m_process->frameCreated(frameID, subFrame.get());
4486}
4487
4488void WebPageProxy::didCreateWindow(FrameIdentifier frameID, GlobalWindowIdentifier&& windowIdentifier)
4489{
4490}
4491
4492double WebPageProxy::estimatedProgress() const
4493{
4494 return m_pageLoadState.estimatedProgress();
4495}
4496
4497void WebPageProxy::didStartProgress()
4498{
4499 ASSERT(!m_isClosed);
4500
4501 PageClientProtector protector(pageClient());
4502
4503 auto transaction = m_pageLoadState.transaction();
4504 m_pageLoadState.didStartProgress(transaction);
4505
4506 m_pageLoadState.commitChanges();
4507}
4508
4509void WebPageProxy::didChangeProgress(double value)
4510{
4511 PageClientProtector protector(pageClient());
4512
4513 auto transaction = m_pageLoadState.transaction();
4514 m_pageLoadState.didChangeProgress(transaction, value);
4515
4516 m_pageLoadState.commitChanges();
4517}
4518
4519void WebPageProxy::didFinishProgress()
4520{
4521 PageClientProtector protector(pageClient());
4522
4523 auto transaction = m_pageLoadState.transaction();
4524 m_pageLoadState.didFinishProgress(transaction);
4525
4526 m_pageLoadState.commitChanges();
4527}
4528
4529void WebPageProxy::setNetworkRequestsInProgress(bool networkRequestsInProgress)
4530{
4531 auto transaction = m_pageLoadState.transaction();
4532 m_pageLoadState.setNetworkRequestsInProgress(transaction, networkRequestsInProgress);
4533}
4534
4535void WebPageProxy::preconnectTo(const URL& url)
4536{
4537 if (!m_websiteDataStore->configuration().allowsServerPreconnect())
4538 return;
4539
4540 auto storedCredentialsPolicy = m_canUseCredentialStorage ? WebCore::StoredCredentialsPolicy::Use : WebCore::StoredCredentialsPolicy::DoNotUse;
4541 websiteDataStore().networkProcess().preconnectTo(sessionID(), identifier(), webPageID(), url, userAgent(), storedCredentialsPolicy, isNavigatingToAppBoundDomain(), m_lastNavigationWasAppBound ? LastNavigationWasAppBound::Yes : LastNavigationWasAppBound::No);
4542}
4543
4544void WebPageProxy::setCanUseCredentialStorage(bool canUseCredentialStorage)
4545{
4546 m_canUseCredentialStorage = canUseCredentialStorage;
4547 send(Messages::WebPage::SetCanUseCredentialStorage(canUseCredentialStorage));
4548}
4549
4550void WebPageProxy::didDestroyNavigation(uint64_t navigationID)
4551{
4552 MESSAGE_CHECK(m_process, WebNavigationState::NavigationMap::isValidKey(navigationID));
4553
4554 PageClientProtector protector(pageClient());
4555
4556 // On process-swap, the previous process tries to destroy the navigation but the provisional process is actually taking over the navigation.
4557 if (m_provisionalPage && m_provisionalPage->navigationID() == navigationID)
4558 return;
4559
4560 m_navigationState->didDestroyNavigation(navigationID);
4561}
4562
4563void WebPageProxy::didStartProvisionalLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData)
4564{
4565 didStartProvisionalLoadForFrameShared(m_process.copyRef(), frameID, WTFMove(frameInfo), WTFMove(request), navigationID, WTFMove(url), WTFMove(unreachableURL), userData);
4566}
4567
4568void WebPageProxy::didStartProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData)
4569{
4570 PageClientProtector protector(pageClient());
4571
4572 auto frame = makeRefPtr(process->webFrame(frameID));
4573 MESSAGE_CHECK(process, frame);
4574 MESSAGE_CHECK_URL(process, url);
4575
4576 // If the page starts a new main frame provisional load, then cancel any pending one in a provisional process.
4577 if (frame->isMainFrame() && m_provisionalPage && m_provisionalPage->mainFrame() != frame) {
4578 m_provisionalPage->cancel();
4579 m_provisionalPage = nullptr;
4580 }
4581
4582 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4583 RefPtr<API::Navigation> navigation;
4584 if (frame->isMainFrame() && navigationID)
4585 navigation = navigationState().navigation(navigationID);
4586
4587 LOG(Loading, "WebPageProxy %" PRIu64 " in process pid %i didStartProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", m_identifier.toUInt64(), process->processIdentifier(), frameID.toUInt64(), navigationID, url.string().utf8().data());
4588 WEBPAGEPROXY_RELEASE_LOG(Loading, "didStartProvisionalLoadForFrame: frameID=%" PRIu64, frameID.toUInt64());
4589
4590 auto transaction = m_pageLoadState.transaction();
4591 m_pageLoadState.clearPendingAPIRequest(transaction);
4592
4593 if (frame->isMainFrame()) {
4594 process->didStartProvisionalLoadForMainFrame(url);
4595 reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
4596 m_pageLoadStart = MonotonicTime::now();
4597 m_pageLoadState.didStartProvisionalLoad(transaction, url.string(), unreachableURL.string());
4598 pageClient().didStartProvisionalLoadForMainFrame();
4599 closeOverlayedViews();
4600 }
4601
4602 frame->setUnreachableURL(unreachableURL);
4603 frame->didStartProvisionalLoad(url);
4604
4605 m_pageLoadState.commitChanges();
4606 if (m_loaderClient)
4607 m_loaderClient->didStartProvisionalLoadForFrame(*this, *frame, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
4608 else {
4609 if (frameInfo.isMainFrame)
4610 m_navigationClient->didStartProvisionalNavigation(*this, request, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
4611 m_navigationClient->didStartProvisionalLoadForFrame(*this, WTFMove(request), WTFMove(frameInfo));
4612 }
4613
4614#if ENABLE(WEB_AUTHN)
4615 m_websiteDataStore->authenticatorManager().cancelRequest(m_webPageID, frameID);
4616#endif
4617}
4618
4619void WebPageProxy::didExplicitOpenForFrame(FrameIdentifier frameID, URL&& url, String&& mimeType)
4620{
4621 auto* frame = m_process->webFrame(frameID);
4622 MESSAGE_CHECK(m_process, frame);
4623
4624 if (!checkURLReceivedFromCurrentOrPreviousWebProcess(m_process, url)) {
4625 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "Ignoring WebPageProxy::DidExplicitOpenForFrame() IPC from the WebContent process because the file URL is outside the sandbox");
4626 return;
4627 }
4628
4629 auto transaction = m_pageLoadState.transaction();
4630
4631 if (frame->isMainFrame())
4632 m_pageLoadState.didExplicitOpen(transaction, url.string());
4633
4634 frame->didExplicitOpen(WTFMove(url), WTFMove(mimeType));
4635
4636 m_hasCommittedAnyProvisionalLoads = true;
4637 m_process->didCommitProvisionalLoad();
4638
4639 m_pageLoadState.commitChanges();
4640}
4641
4642void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(FrameIdentifier frameID, uint64_t navigationID, ResourceRequest&& request, const UserData& userData)
4643{
4644 didReceiveServerRedirectForProvisionalLoadForFrameShared(m_process.copyRef(), frameID, navigationID, WTFMove(request), userData);
4645}
4646
4647void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, uint64_t navigationID, ResourceRequest&& request, const UserData& userData)
4648{
4649 LOG(Loading, "WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", frameID.toUInt64(), navigationID, request.url().string().utf8().data());
4650 WEBPAGEPROXY_RELEASE_LOG(Loading, "didReceiveServerRedirectForProvisionalLoadForFrame: frameID=%" PRIu64, frameID.toUInt64());
4651
4652 PageClientProtector protector(pageClient());
4653
4654 WebFrameProxy* frame = process->webFrame(frameID);
4655 MESSAGE_CHECK(process, frame);
4656 MESSAGE_CHECK_URL(process, request.url());
4657
4658 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4659 RefPtr<API::Navigation> navigation = navigationID ? navigationState().navigation(navigationID) : nullptr;
4660 if (navigation)
4661 navigation->appendRedirectionURL(request.url());
4662
4663 auto transaction = m_pageLoadState.transaction();
4664
4665 if (frame->isMainFrame())
4666 m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, request.url().string());
4667
4668 frame->didReceiveServerRedirectForProvisionalLoad(request.url());
4669
4670 m_pageLoadState.commitChanges();
4671 if (m_loaderClient)
4672 m_loaderClient->didReceiveServerRedirectForProvisionalLoadForFrame(*this, *frame, frame->isMainFrame() ? navigation.get() : nullptr, process->transformHandlesToObjects(userData.object()).get());
4673 else if (frame->isMainFrame())
4674 m_navigationClient->didReceiveServerRedirectForProvisionalNavigation(*this, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
4675}
4676
4677void WebPageProxy::willPerformClientRedirectForFrame(FrameIdentifier frameID, const String& url, double delay, WebCore::LockBackForwardList)
4678{
4679 WEBPAGEPROXY_RELEASE_LOG(Loading, "willPerformClientRedirectForFrame: frameID=%" PRIu64, frameID.toUInt64());
4680
4681 PageClientProtector protector(pageClient());
4682
4683 WebFrameProxy* frame = m_process->webFrame(frameID);
4684 MESSAGE_CHECK(m_process, frame);
4685
4686 if (frame->isMainFrame())
4687 m_navigationClient->willPerformClientRedirect(*this, url, delay);
4688}
4689
4690void WebPageProxy::didCancelClientRedirectForFrame(FrameIdentifier frameID)
4691{
4692 WEBPAGEPROXY_RELEASE_LOG(Loading, "didCancelClientRedirectForFrame: frameID=%" PRIu64, frameID.toUInt64());
4693
4694 PageClientProtector protector(pageClient());
4695
4696 WebFrameProxy* frame = m_process->webFrame(frameID);
4697 MESSAGE_CHECK(m_process, frame);
4698
4699 if (frame->isMainFrame())
4700 m_navigationClient->didCancelClientRedirect(*this);
4701}
4702
4703void WebPageProxy::didChangeProvisionalURLForFrame(FrameIdentifier frameID, uint64_t navigationID, URL&& url)
4704{
4705 didChangeProvisionalURLForFrameShared(m_process.copyRef(), frameID, navigationID, WTFMove(url));
4706}
4707
4708void WebPageProxy::didChangeProvisionalURLForFrameShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, uint64_t, URL&& url)
4709{
4710 PageClientProtector protector(pageClient());
4711
4712 WebFrameProxy* frame = process->webFrame(frameID);
4713 MESSAGE_CHECK(process, frame);
4714 MESSAGE_CHECK(process, frame->frameLoadState().state() == FrameLoadState::State::Provisional);
4715 MESSAGE_CHECK_URL(process, url);
4716
4717 auto transaction = m_pageLoadState.transaction();
4718
4719 // Internally, we handle this the same way we handle a server redirect. There are no client callbacks
4720 // for this, but if this is the main frame, clients may observe a change to the page's URL.
4721 if (frame->isMainFrame())
4722 m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, url.string());
4723
4724 frame->didReceiveServerRedirectForProvisionalLoad(url);
4725}
4726
4727void WebPageProxy::didFailProvisionalLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, WebCore::ResourceRequest&& request, uint64_t navigationID, const String& provisionalURL, const ResourceError& error, WillContinueLoading willContinueLoading, const UserData& userData)
4728{
4729 if (m_provisionalPage && m_provisionalPage->navigationID() == navigationID) {
4730 // The load did not fail, it is merely happening in a new provisional process.
4731 return;
4732 }
4733
4734 didFailProvisionalLoadForFrameShared(m_process.copyRef(), frameID, WTFMove(frameInfo), WTFMove(request), navigationID, provisionalURL, error, willContinueLoading, userData);
4735}
4736
4737void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, FrameInfoData&& frameInfo, WebCore::ResourceRequest&& request, uint64_t navigationID, const String& provisionalURL, const ResourceError& error, WillContinueLoading willContinueLoading, const UserData& userData)
4738{
4739 LOG(Loading, "(Loading) WebPageProxy %" PRIu64 " in web process pid %i didFailProvisionalLoadForFrame to provisionalURL %s", m_identifier.toUInt64(), process->processIdentifier(), provisionalURL.utf8().data());
4740 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "didFailProvisionalLoadForFrame: frameID=%" PRIu64 ", domain=%s, code=%d", frameID.toUInt64(), error.domain().utf8().data(), error.errorCode());
4741
4742 PageClientProtector protector(pageClient());
4743
4744 WebFrameProxy* frame = process->webFrame(frameID);
4745 MESSAGE_CHECK(process, frame);
4746
4747 if (m_controlledByAutomation) {
4748 if (auto* automationSession = process->processPool().automationSession())
4749 automationSession->navigationOccurredForFrame(*frame);
4750 }
4751
4752 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4753 RefPtr<API::Navigation> navigation;
4754 if (frame->isMainFrame() && navigationID)
4755 navigation = navigationState().takeNavigation(navigationID);
4756
4757 auto transaction = m_pageLoadState.transaction();
4758
4759 if (frame->isMainFrame()) {
4760 reportPageLoadResult(error);
4761 m_pageLoadState.didFailProvisionalLoad(transaction);
4762 pageClient().didFailProvisionalLoadForMainFrame();
4763 if (navigation)
4764 navigation->setClientNavigationActivity(nullptr);
4765 }
4766
4767 frame->didFailProvisionalLoad();
4768
4769 m_pageLoadState.commitChanges();
4770
4771 ASSERT(!m_failingProvisionalLoadURL);
4772 m_failingProvisionalLoadURL = provisionalURL;
4773
4774 if (m_loaderClient)
4775 m_loaderClient->didFailProvisionalLoadWithErrorForFrame(*this, *frame, navigation.get(), error, process->transformHandlesToObjects(userData.object()).get());
4776 else {
4777 m_navigationClient->didFailProvisionalNavigationWithError(*this, FrameInfoData { frameInfo }, navigation.get(), error, process->transformHandlesToObjects(userData.object()).get());
4778 m_navigationClient->didFailProvisionalLoadWithErrorForFrame(*this, WTFMove(request), error, WTFMove(frameInfo));
4779 }
4780
4781 m_failingProvisionalLoadURL = { };
4782
4783 // If the provisional page's load fails then we destroy the provisional page.
4784 if (m_provisionalPage && m_provisionalPage->mainFrame() == frame && willContinueLoading == WillContinueLoading::No)
4785 m_provisionalPage = nullptr;
4786}
4787
4788#if ENABLE(RESOURCE_LOAD_STATISTICS)
4789static OptionSet<CrossSiteNavigationDataTransfer::Flag> checkIfNavigationContainsDataTransfer(const SecurityOriginData requesterOrigin, const ResourceRequest& currentRequest)
4790{
4791 OptionSet<CrossSiteNavigationDataTransfer::Flag> navigationDataTransfer;
4792 if (requesterOrigin.securityOrigin()->isUnique())
4793 return navigationDataTransfer;
4794
4795 auto currentURL = currentRequest.url();
4796 if (!currentURL.query().isEmpty() || !currentURL.fragmentIdentifier().isEmpty())
4797 navigationDataTransfer.add(CrossSiteNavigationDataTransfer::Flag::DestinationLinkDecoration);
4798
4799 URL referrerURL { URL(), currentRequest.httpReferrer() };
4800 if (!referrerURL.query().isEmpty() || !referrerURL.fragmentIdentifier().isEmpty())
4801 navigationDataTransfer.add(CrossSiteNavigationDataTransfer::Flag::ReferrerLinkDecoration);
4802
4803 return navigationDataTransfer;
4804}
4805#endif
4806
4807void WebPageProxy::didCommitLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, WebCore::FrameLoadType frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool usedLegacyTLS, bool containsPluginDocument, std::optional<HasInsecureContent> hasInsecureContent, WebCore::MouseEventPolicy mouseEventPolicy, const UserData& userData)
4808{
4809 LOG(Loading, "(Loading) WebPageProxy %" PRIu64 " didCommitLoadForFrame in navigation %" PRIu64, m_identifier.toUInt64(), navigationID);
4810 LOG(BackForward, "(Back/Forward) After load commit, back/forward list is now:%s", m_backForwardList->loggingString());
4811 WEBPAGEPROXY_RELEASE_LOG(Loading, "didCommitLoadForFrame: frameID=%" PRIu64, frameID.toUInt64());
4812
4813 PageClientProtector protector(pageClient());
4814
4815 WebFrameProxy* frame = m_process->webFrame(frameID);
4816 MESSAGE_CHECK(m_process, frame);
4817
4818 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4819 RefPtr<API::Navigation> navigation;
4820 if (frame->isMainFrame() && navigationID && (navigation = navigationState().navigation(navigationID))) {
4821#if ENABLE(RESOURCE_LOAD_STATISTICS)
4822 auto requesterOrigin = navigation->lastNavigationAction().requesterOrigin;
4823 auto currentRequest = navigation->currentRequest();
4824 auto navigationDataTransfer = checkIfNavigationContainsDataTransfer(requesterOrigin, currentRequest);
4825 if (!navigationDataTransfer.isEmpty()) {
4826 RegistrableDomain currentDomain { currentRequest.url() };
4827 URL requesterURL { URL(), requesterOrigin.toString() };
4828 if (!currentDomain.matches(requesterURL))
4829 m_websiteDataStore->networkProcess().didCommitCrossSiteLoadWithDataTransfer(m_websiteDataStore->sessionID(), RegistrableDomain { requesterURL }, currentDomain, navigationDataTransfer, m_identifier, m_webPageID);
4830 }
4831#endif
4832 }
4833
4834 m_hasCommittedAnyProvisionalLoads = true;
4835 m_process->didCommitProvisionalLoad();
4836
4837 if (frame->isMainFrame()) {
4838 m_hasUpdatedRenderingAfterDidCommitLoad = false;
4839#if PLATFORM(IOS_FAMILY)
4840 m_firstLayerTreeTransactionIdAfterDidCommitLoad = downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea()).nextLayerTreeTransactionID();
4841#endif
4842 }
4843
4844 auto transaction = m_pageLoadState.transaction();
4845 Ref<WebCertificateInfo> webCertificateInfo = WebCertificateInfo::create(certificateInfo);
4846 bool markPageInsecure = hasInsecureContent ? hasInsecureContent.value() == HasInsecureContent::Yes : certificateInfo.containsNonRootSHA1SignedCertificate();
4847
4848 if (frame->isMainFrame()) {
4849 m_pageLoadState.didCommitLoad(transaction, webCertificateInfo, markPageInsecure, usedLegacyTLS);
4850 m_shouldSuppressNextAutomaticNavigationSnapshot = false;
4851 } else if (markPageInsecure)
4852 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
4853
4854#if USE(APPKIT)
4855 // FIXME (bug 59111): didCommitLoadForFrame comes too late when restoring a page from b/f cache, making us disable secure event mode in password fields.
4856 // FIXME: A load going on in one frame shouldn't affect text editing in other frames on the page.
4857 pageClient().resetSecureInputState();
4858#endif
4859
4860 frame->didCommitLoad(mimeType, webCertificateInfo, containsPluginDocument);
4861
4862 if (frame->isMainFrame()) {
4863 std::optional<WebCore::PrivateClickMeasurement> privateClickMeasurement;
4864 if (m_privateClickMeasurement)
4865 privateClickMeasurement = m_privateClickMeasurement;
4866 else if (navigation && navigation->privateClickMeasurement())
4867 privateClickMeasurement = navigation->privateClickMeasurement();
4868 if (privateClickMeasurement) {
4869 if (privateClickMeasurement->destinationSite().matches(frame->url()))
4870 websiteDataStore().networkProcess().send(Messages::NetworkProcess::StorePrivateClickMeasurement(m_websiteDataStore->sessionID(), *privateClickMeasurement), 0);
4871 }
4872 }
4873 m_privateClickMeasurement.reset();
4874
4875 if (frame->isMainFrame()) {
4876 m_mainFrameHasCustomContentProvider = frameHasCustomContentProvider;
4877
4878 if (m_mainFrameHasCustomContentProvider) {
4879 // Always assume that the main frame is pinned here, since the custom representation view will handle
4880 // any wheel events and dispatch them to the WKView when necessary.
4881 m_mainFrameIsPinnedToLeftSide = true;
4882 m_mainFrameIsPinnedToRightSide = true;
4883 m_mainFrameIsPinnedToTopSide = true;
4884 m_mainFrameIsPinnedToBottomSide = true;
4885
4886 m_uiClient->pinnedStateDidChange(*this);
4887 }
4888 pageClient().didCommitLoadForMainFrame(mimeType, frameHasCustomContentProvider);
4889 }
4890
4891 // Even if WebPage has the default pageScaleFactor (and therefore doesn't reset it),
4892 // WebPageProxy's cache of the value can get out of sync (e.g. in the case where a
4893 // plugin is handling page scaling itself) so we should reset it to the default
4894 // for standard main frame loads.
4895 if (frame->isMainFrame()) {
4896 if (frameLoadType == FrameLoadType::Standard) {
4897 m_pageScaleFactor = 1;
4898 m_pluginScaleFactor = 1;
4899 m_mainFramePluginHandlesPageScaleGesture = false;
4900 }
4901#if ENABLE(POINTER_LOCK)
4902 requestPointerUnlock();
4903#endif
4904 pageClient().setMouseEventPolicy(mouseEventPolicy);
4905#if ENABLE(UI_PROCESS_PDF_HUD)
4906 pageClient().removeAllPDFHUDs();
4907#endif
4908 }
4909
4910 m_pageLoadState.commitChanges();
4911 if (m_loaderClient)
4912 m_loaderClient->didCommitLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4913 else {
4914 if (frameInfo.isMainFrame)
4915 m_navigationClient->didCommitNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4916 m_navigationClient->didCommitLoadForFrame(*this, WTFMove(request), WTFMove(frameInfo));
4917 }
4918 if (frame->isMainFrame()) {
4919#if ENABLE(ATTACHMENT_ELEMENT)
4920 invalidateAllAttachments();
4921#endif
4922#if ENABLE(REMOTE_INSPECTOR)
4923 remoteInspectorInformationDidChange();
4924#endif
4925#if USE(APPKIT)
4926 closeSharedPreviewPanelIfNecessary();
4927#endif
4928 }
4929
4930#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
4931 if (frame->isMainFrame())
4932 GroupActivitiesSessionNotifier::sharedNotifier().webPageURLChanged(*this);
4933#endif
4934}
4935
4936void WebPageProxy::didFinishDocumentLoadForFrame(FrameIdentifier frameID, uint64_t navigationID, const UserData& userData)
4937{
4938 WEBPAGEPROXY_RELEASE_LOG(Loading, "didFinishDocumentLoadForFrame: frameID=%" PRIu64, frameID.toUInt64());
4939
4940 PageClientProtector protector(pageClient());
4941
4942 WebFrameProxy* frame = m_process->webFrame(frameID);
4943 MESSAGE_CHECK(m_process, frame);
4944
4945 if (m_controlledByAutomation) {
4946 if (auto* automationSession = process().processPool().automationSession())
4947 automationSession->documentLoadedForFrame(*frame);
4948 }
4949
4950 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4951 RefPtr<API::Navigation> navigation;
4952 if (frame->isMainFrame() && navigationID)
4953 navigation = navigationState().navigation(navigationID);
4954
4955 if (frame->isMainFrame()) {
4956 m_navigationClient->didFinishDocumentLoad(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4957#if ENABLE(RESOURCE_LOAD_STATISTICS)
4958 m_didFinishDocumentLoadForMainFrameTimestamp = MonotonicTime::now();
4959#endif
4960 }
4961}
4962
4963void WebPageProxy::didFinishLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const UserData& userData)
4964{
4965 LOG(Loading, "WebPageProxy::didFinishLoadForFrame - WebPageProxy %p with navigationID %" PRIu64 " didFinishLoad", this, navigationID);
4966 WEBPAGEPROXY_RELEASE_LOG(Loading, "didFinishLoadForFrame: frameID=%" PRIu64, frameID.toUInt64());
4967
4968 PageClientProtector protector(pageClient());
4969
4970 WebFrameProxy* frame = m_process->webFrame(frameID);
4971 MESSAGE_CHECK(m_process, frame);
4972
4973 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4974 RefPtr<API::Navigation> navigation;
4975 if (frame->isMainFrame() && navigationID)
4976 navigation = navigationState().navigation(navigationID);
4977
4978 auto transaction = m_pageLoadState.transaction();
4979
4980 bool isMainFrame = frame->isMainFrame();
4981 if (isMainFrame)
4982 m_pageLoadState.didFinishLoad(transaction);
4983
4984 if (m_controlledByAutomation) {
4985 if (auto* automationSession = process().processPool().automationSession())
4986 automationSession->navigationOccurredForFrame(*frame);
4987 }
4988
4989 frame->didFinishLoad();
4990
4991 m_pageLoadState.commitChanges();
4992 if (m_loaderClient)
4993 m_loaderClient->didFinishLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4994 else {
4995 if (frameInfo.isMainFrame)
4996 m_navigationClient->didFinishNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4997 m_navigationClient->didFinishLoadForFrame(*this, WTFMove(request), WTFMove(frameInfo));
4998 }
4999
5000 if (isMainFrame) {
5001 reportPageLoadResult();
5002 pageClient().didFinishNavigation(navigation.get());
5003
5004 if (navigation)
5005 navigation->setClientNavigationActivity(nullptr);
5006
5007 resetRecentCrashCountSoon();
5008
5009 notifyProcessPoolToPrewarm();
5010 }
5011
5012 m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = false;
5013}
5014
5015void WebPageProxy::didFailLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const ResourceError& error, const UserData& userData)
5016{
5017 WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "didFailLoadForFrame: frameID=%" PRIu64 ", domain=%s, code=%d", frameID.toUInt64(), error.domain().utf8().data(), error.errorCode());
5018
5019 PageClientProtector protector(pageClient());
5020
5021 WebFrameProxy* frame = m_process->webFrame(frameID);
5022 MESSAGE_CHECK(m_process, frame);
5023
5024 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
5025 RefPtr<API::Navigation> navigation;
5026 if (frame->isMainFrame() && navigationID)
5027 navigation = navigationState().navigation(navigationID);
5028
5029 auto transaction = m_pageLoadState.transaction();
5030
5031 bool isMainFrame = frame->isMainFrame();
5032
5033 if (isMainFrame)
5034 m_pageLoadState.didFailLoad(transaction);
5035
5036 if (m_controlledByAutomation) {
5037 if (auto* automationSession = process().processPool().automationSession())
5038 automationSession->navigationOccurredForFrame(*frame);
5039 }
5040
5041 frame->didFailLoad();
5042
5043 m_pageLoadState.commitChanges();
5044 if (m_loaderClient)
5045 m_loaderClient->didFailLoadWithErrorForFrame(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get());
5046 else {
5047 if (frameInfo.isMainFrame)
5048 m_navigationClient->didFailNavigationWithError(*this, frameInfo, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get());
5049 m_navigationClient->didFailLoadWithErrorForFrame(*this, WTFMove(request), error, WTFMove(frameInfo));
5050 }
5051
5052 if (isMainFrame) {
5053 reportPageLoadResult(error);
5054 pageClient().didFailNavigation(navigation.get());
5055 if (navigation)
5056 navigation->setClientNavigationActivity(nullptr);
5057 }
5058}
5059
5060void WebPageProxy::didSameDocumentNavigationForFrame(FrameIdentifier frameID, uint64_t navigationID, uint32_t opaqueSameDocumentNavigationType, URL&& url, const UserData& userData)
5061{
5062 WEBPAGEPROXY_RELEASE_LOG(Loading, "didSameDocumentNavigationForFrame: frameID=%" PRIu64, frameID.toUInt64());
5063
5064 PageClientProtector protector(pageClient());
5065
5066 WebFrameProxy* frame = m_process->webFrame(frameID);
5067 MESSAGE_CHECK(m_process, frame);
5068 MESSAGE_CHECK_URL(m_process, url);
5069
5070 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
5071 RefPtr<API::Navigation> navigation;
5072 if (frame->isMainFrame() && navigationID)
5073 navigation = navigationState().navigation(navigationID);
5074
5075 auto transaction = m_pageLoadState.transaction();
5076
5077 bool isMainFrame = frame->isMainFrame();
5078 if (isMainFrame)
5079 m_pageLoadState.didSameDocumentNavigation(transaction, url.string());
5080
5081 if (m_controlledByAutomation) {
5082 if (auto* automationSession = process().processPool().automationSession())
5083 automationSession->navigationOccurredForFrame(*frame);
5084 }
5085
5086 m_pageLoadState.clearPendingAPIRequest(transaction);
5087 frame->didSameDocumentNavigation(url);
5088
5089 m_pageLoadState.commitChanges();
5090
5091 SameDocumentNavigationType navigationType = static_cast<SameDocumentNavigationType>(opaqueSameDocumentNavigationType);
5092 if (isMainFrame)
5093 m_navigationClient->didSameDocumentNavigation(*this, navigation.get(), navigationType, m_process->transformHandlesToObjects(userData.object()).get());
5094
5095 if (isMainFrame)
5096 pageClient().didSameDocumentNavigationForMainFrame(navigationType);
5097}
5098
5099void WebPageProxy::didChangeMainDocument(FrameIdentifier frameID)
5100{
5101#if ENABLE(MEDIA_STREAM)
5102 if (m_userMediaPermissionRequestManager)
5103 m_userMediaPermissionRequestManager->resetAccess(frameID);
5104#else
5105 UNUSED_PARAM(frameID);
5106#endif
5107 m_isQuotaIncreaseDenied = false;
5108
5109 m_speechRecognitionPermissionManager = nullptr;
5110}
5111
5112void WebPageProxy::viewIsBecomingVisible()
5113{
5114#if ENABLE(MEDIA_STREAM)
5115 if (m_userMediaPermissionRequestManager)
5116 m_userMediaPermissionRequestManager->viewIsBecomingVisible();
5117#endif
5118}
5119
5120void WebPageProxy::didReceiveTitleForFrame(FrameIdentifier frameID, const String& title, const UserData& userData)
5121{
5122 PageClientProtector protector(pageClient());
5123
5124 WebFrameProxy* frame = m_process->webFrame(frameID);
5125 MESSAGE_CHECK(m_process, frame);
5126
5127 auto transaction = m_pageLoadState.transaction();
5128
5129 if (frame->isMainFrame())
5130 m_pageLoadState.setTitle(transaction, title);
5131
5132 frame->didChangeTitle(title);
5133
5134 m_pageLoadState.commitChanges();
5135
5136#if ENABLE(REMOTE_INSPECTOR)
5137 if (frame->isMainFrame())
5138 remoteInspectorInformationDidChange();
5139#endif
5140}
5141
5142void WebPageProxy::didFirstLayoutForFrame(FrameIdentifier, const UserData& userData)
5143{
5144}
5145
5146void WebPageProxy::didFirstVisuallyNonEmptyLayoutForFrame(FrameIdentifier frameID, const UserData& userData)
5147{
5148 PageClientProtector protector(pageClient());
5149
5150 WebFrameProxy* frame = m_process->webFrame(frameID);
5151 MESSAGE_CHECK(m_process, frame);
5152
5153 if (m_loaderClient)
5154 m_loaderClient->didFirstVisuallyNonEmptyLayoutForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get());
5155
5156 if (frame->isMainFrame())
5157 pageClient().didFirstVisuallyNonEmptyLayoutForMainFrame();
5158}
5159
5160void WebPageProxy::didLayoutForCustomContentProvider()
5161{
5162 didReachLayoutMilestone({ DidFirstLayout, DidFirstVisuallyNonEmptyLayout, DidHitRelevantRepaintedObjectsAreaThreshold });
5163}
5164
5165void WebPageProxy::didReachLayoutMilestone(OptionSet<WebCore::LayoutMilestone> layoutMilestones)
5166{
5167 PageClientProtector protector(pageClient());
5168
5169 if (layoutMilestones.contains(DidFirstVisuallyNonEmptyLayout))
5170 pageClient().clearSafeBrowsingWarningIfForMainFrameNavigation();
5171
5172 if (m_loaderClient)
5173 m_loaderClient->didReachLayoutMilestone(*this, layoutMilestones);
5174 m_navigationClient->renderingProgressDidChange(*this, layoutMilestones);
5175}
5176
5177void WebPageProxy::didDisplayInsecureContentForFrame(FrameIdentifier frameID, const UserData& userData)
5178{
5179 PageClientProtector protector(pageClient());
5180
5181 WebFrameProxy* frame = m_process->webFrame(frameID);
5182 MESSAGE_CHECK(m_process, frame);
5183
5184 auto transaction = m_pageLoadState.transaction();
5185 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
5186 m_pageLoadState.commitChanges();
5187
5188 m_navigationClient->didDisplayInsecureContent(*this, m_process->transformHandlesToObjects(userData.object()).get());
5189}
5190
5191void WebPageProxy::didRunInsecureContentForFrame(FrameIdentifier frameID, const UserData& userData)
5192{
5193 PageClientProtector protector(pageClient());
5194
5195 WebFrameProxy* frame = m_process->webFrame(frameID);
5196 MESSAGE_CHECK(m_process, frame);
5197
5198 auto transaction = m_pageLoadState.transaction();
5199 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
5200 m_pageLoadState.commitChanges();
5201
5202 m_navigationClient->didRunInsecureContent(*this, m_process->transformHandlesToObjects(userData.object()).get());
5203}
5204
5205void WebPageProxy::didDetectXSSForFrame(FrameIdentifier, const UserData&)
5206{
5207}
5208
5209void WebPageProxy::mainFramePluginHandlesPageScaleGestureDidChange(bool mainFramePluginHandlesPageScaleGesture)
5210{
5211 m_mainFramePluginHandlesPageScaleGesture = mainFramePluginHandlesPageScaleGesture;
5212}
5213
5214#if !PLATFORM(COCOA)
5215void WebPageProxy::beginSafeBrowsingCheck(const URL&, bool, WebFramePolicyListenerProxy& listener)
5216{
5217 listener.didReceiveSafeBrowsingResults({ });
5218}
5219#endif
5220
5221void WebPageProxy::decidePolicyForNavigationActionAsync(FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, uint64_t navigationID,
5222 NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request,
5223 IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, uint64_t listenerID)
5224{
5225 decidePolicyForNavigationActionAsyncShared(m_process.copyRef(), m_webPageID, frameID, WTFMove(frameInfo), identifier, navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, listenerID);
5226}
5227
5228void WebPageProxy::decidePolicyForNavigationActionAsyncShared(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, FrameIdentifier frameID, FrameInfoData&& frameInfo,
5229 WebCore::PolicyCheckIdentifier identifier, uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID,
5230 const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse,
5231 const UserData& userData, uint64_t listenerID)
5232{
5233 auto* frame = process->webFrame(frameID);
5234 MESSAGE_CHECK(process, frame);
5235
5236 auto sender = PolicyDecisionSender::create(identifier, [webPageID, frameID, listenerID, process] (const auto& policyDecision) {
5237 process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, policyDecision, createNetworkExtensionsSandboxExtensions(process)), webPageID);
5238 });
5239
5240 decidePolicyForNavigationAction(process.copyRef(), *frame, WTFMove(frameInfo), navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID,
5241 originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, WTFMove(sender));
5242}
5243
5244void WebPageProxy::decidePolicyForNavigationAction(Ref<WebProcessProxy>&& process, WebFrameProxy& frame, FrameInfoData&& frameInfo, uint64_t navigationID,
5245 NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfoData, std::optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request,
5246 IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, Ref<PolicyDecisionSender>&& sender)
5247{
5248 WEBPAGEPROXY_RELEASE_LOG(Loading, "decidePolicyForNavigationAction: frameID=%llu, navigationID=%llu", frame.frameID().toUInt64(), navigationID);
5249
5250 LOG(Loading, "WebPageProxy::decidePolicyForNavigationAction - Original URL %s, current target URL %s", originalRequest.url().string().utf8().data(), request.url().string().utf8().data());
5251
5252 PageClientProtector protector(pageClient());
5253
5254 // Make the request whole again as we do not normally encode the request's body when sending it over IPC, for performance reasons.
5255 request.setHTTPBody(requestBody.takeData());
5256
5257 auto transaction = m_pageLoadState.transaction();
5258
5259 bool fromAPI = request.url() == m_pageLoadState.pendingAPIRequestURL();
5260 if (navigationID && !fromAPI)
5261 m_pageLoadState.clearPendingAPIRequest(transaction);
5262
5263 if (!checkURLReceivedFromCurrentOrPreviousWebProcess(process, request.url())) {
5264 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "Ignoring request to load this main resource because it is outside the sandbox");
5265 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Ignore, 0, std::nullopt, std::nullopt });
5266 return;
5267 }
5268
5269 MESSAGE_CHECK_URL(process, originalRequest.url());
5270
5271 RefPtr<API::Navigation> navigation;
5272 if (navigationID)
5273 navigation = m_navigationState->navigation(navigationID);
5274
5275 // When process-swapping on a redirect, the navigationActionData / originatingFrameInfoData provided by the fresh new WebProcess are inaccurate since
5276 // the new process does not have sufficient information. To address the issue, we restore the information we stored on the NavigationAction during the original request
5277 // policy decision.
5278 if (navigationActionData.isRedirect && navigation) {
5279 navigationActionData = navigation->lastNavigationAction();
5280 navigationActionData.isRedirect = true;
5281 originatingFrameInfoData = navigation->originatingFrameInfo();
5282 frameInfo.securityOrigin = navigation->destinationFrameSecurityOrigin();
5283 }
5284
5285 if (!navigation) {
5286 if (auto targetBackForwardItemIdentifier = navigationActionData.targetBackForwardItemIdentifier) {
5287 if (auto* item = m_backForwardList->itemForID(*targetBackForwardItemIdentifier)) {
5288 auto* fromItem = navigationActionData.sourceBackForwardItemIdentifier ? m_backForwardList->itemForID(*navigationActionData.sourceBackForwardItemIdentifier) : nullptr;
5289 if (!fromItem)
5290 fromItem = m_backForwardList->currentItem();
5291 navigation = m_navigationState->createBackForwardNavigation(*item, fromItem, FrameLoadType::IndexedBackForward);
5292 }
5293 }
5294 if (!navigation)
5295 navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
5296 }
5297
5298 navigationID = navigation->navigationID();
5299
5300 // Make sure the provisional page always has the latest navigationID.
5301 if (m_provisionalPage && &m_provisionalPage->process() == process.ptr())
5302 m_provisionalPage->setNavigationID(navigationID);
5303
5304 navigation->setCurrentRequest(ResourceRequest(request), process->coreProcessIdentifier());
5305 navigation->setLastNavigationAction(navigationActionData);
5306 navigation->setOriginatingFrameInfo(originatingFrameInfoData);
5307 navigation->setDestinationFrameSecurityOrigin(frameInfo.securityOrigin);
5308
5309 API::Navigation* mainFrameNavigation = frame.isMainFrame() ? navigation.get() : nullptr;
5310 WebFrameProxy* originatingFrame = originatingFrameInfoData.frameID ? process->webFrame(*originatingFrameInfoData.frameID) : nullptr;
5311 auto destinationFrameInfo = API::FrameInfo::create(FrameInfoData { frameInfo }, this);
5312 RefPtr<API::FrameInfo> sourceFrameInfo;
5313 if (!fromAPI && originatingFrame == &frame)
5314 sourceFrameInfo = destinationFrameInfo.copyRef();
5315 else if (!fromAPI) {
5316 auto* originatingPage = originatingPageID ? process->webPage(*originatingPageID) : nullptr;
5317 sourceFrameInfo = API::FrameInfo::create(WTFMove(originatingFrameInfoData), originatingPage);
5318 }
5319
5320 bool shouldOpenAppLinks = !m_shouldSuppressAppLinksInNextNavigationPolicyDecision
5321 && destinationFrameInfo->isMainFrame()
5322 && (m_mainFrame && m_mainFrame->url().host() != request.url().host())
5323 && navigationActionData.navigationType != WebCore::NavigationType::BackForward;
5324
5325 auto userInitiatedActivity = process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
5326 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), destinationFrameInfo.ptr(), std::nullopt, ResourceRequest(request), originalRequest.url(), shouldOpenAppLinks, WTFMove(userInitiatedActivity), mainFrameNavigation);
5327
5328#if ENABLE(CONTENT_FILTERING)
5329 if (frame.didHandleContentFilterUnblockNavigation(request)) {
5330 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "Ignoring request to load this main resource because it was handled by content filter");
5331 return receivedPolicyDecision(PolicyAction::Ignore, m_navigationState->navigation(navigationID), nullptr, WTFMove(navigationAction), WTFMove(sender));
5332 }
5333#endif
5334
5335 ShouldExpectSafeBrowsingResult shouldExpectSafeBrowsingResult = ShouldExpectSafeBrowsingResult::Yes;
5336 if (!m_preferences->safeBrowsingEnabled())
5337 shouldExpectSafeBrowsingResult = ShouldExpectSafeBrowsingResult::No;
5338
5339 ShouldExpectAppBoundDomainResult shouldExpectAppBoundDomainResult = ShouldExpectAppBoundDomainResult::No;
5340#if ENABLE(APP_BOUND_DOMAINS)
5341 shouldExpectAppBoundDomainResult = ShouldExpectAppBoundDomainResult::Yes;
5342#endif
5343
5344 auto listener = makeRef(frame.setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), frame = makeRef(frame), sender = WTFMove(sender), navigation, navigationAction, frameInfo, userDataObject = process->transformHandlesToObjects(userData.object()).get()] (PolicyAction policyAction, API::WebsitePolicies* policies, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning, std::optional<NavigatingToAppBoundDomain> isAppBoundDomain) mutable {
5345 WEBPAGEPROXY_RELEASE_LOG(Loading, "decidePolicyForNavigationAction: listener called: frameID=%llu, navigationID=%llu, policyAction=%u, safeBrowsingWarning=%d, isAppBoundDomain=%d", frame->frameID().toUInt64(), navigation ? navigation->navigationID() : 0, (unsigned)policyAction, !!safeBrowsingWarning, !!isAppBoundDomain);
5346
5347 auto completionHandler = [this, protectedThis, frame, sender = WTFMove(sender), navigation, navigationAction = WTFMove(navigationAction), processSwapRequestedByClient, policies = makeRefPtr(policies)] (PolicyAction policyAction) mutable {
5348 if (frame->isMainFrame()) {
5349 if (!policies) {
5350 if (auto* defaultPolicies = m_configuration->defaultWebsitePolicies())
5351 policies = defaultPolicies->copy();
5352 }
5353 if (policies)
5354 navigation->setEffectiveContentMode(effectiveContentModeAfterAdjustingPolicies(*policies, navigation->currentRequest()));
5355 }
5356 receivedNavigationPolicyDecision(policyAction, navigation.get(), WTFMove(navigationAction), processSwapRequestedByClient, frame, WTFMove(policies), WTFMove(sender));
5357 };
5358
5359#if ENABLE(APP_BOUND_DOMAINS)
5360 if (policyAction != PolicyAction::Ignore) {
5361 if (!setIsNavigatingToAppBoundDomainAndCheckIfPermitted(frame->isMainFrame(), navigation->currentRequest().url(), isAppBoundDomain)) {
5362 auto error = errorForUnpermittedAppBoundDomainNavigation(navigation->currentRequest().url());
5363 m_navigationClient->didFailProvisionalNavigationWithError(*this, FrameInfoData { frameInfo }, navigation.get(), error, userDataObject);
5364 WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "Ignoring request to load this main resource because it is attempting to navigate away from an app-bound domain or navigate after using restricted APIs");
5365 completionHandler(PolicyAction::Ignore);
5366 return;
5367 }
5368 if (frame->isMainFrame())
5369 m_isTopFrameNavigatingToAppBoundDomain = m_isNavigatingToAppBoundDomain;
5370 }
5371#endif
5372
5373 if (!m_pageClient)
5374 return completionHandler(policyAction);
5375
5376 m_pageClient->clearSafeBrowsingWarning();
5377
5378 if (safeBrowsingWarning) {
5379 if (frame->isMainFrame() && safeBrowsingWarning->url().isValid()) {
5380 auto transaction = m_pageLoadState.transaction();
5381 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), safeBrowsingWarning->url().string() });
5382 m_pageLoadState.commitChanges();
5383 }
5384
5385 auto transaction = m_pageLoadState.transaction();
5386 m_pageLoadState.setTitleFromSafeBrowsingWarning(transaction, safeBrowsingWarning->title());
5387
5388 m_pageClient->showSafeBrowsingWarning(*safeBrowsingWarning, [this, protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), policyAction] (auto&& result) mutable {
5389
5390 auto transaction = m_pageLoadState.transaction();
5391 m_pageLoadState.setTitleFromSafeBrowsingWarning(transaction, { });
5392
5393 switchOn(result, [&] (const URL& url) {
5394 completionHandler(PolicyAction::Ignore);
5395 loadRequest({ url });
5396 }, [&] (ContinueUnsafeLoad continueUnsafeLoad) {
5397 switch (continueUnsafeLoad) {
5398 case ContinueUnsafeLoad::No:
5399 if (!hasCommittedAnyProvisionalLoads())
5400 m_uiClient->close(protectedThis.ptr());
5401 completionHandler(PolicyAction::Ignore);
5402 break;
5403 case ContinueUnsafeLoad::Yes:
5404 completionHandler(policyAction);
5405 break;
5406 }
5407 });
5408 });
5409 m_uiClient->didShowSafeBrowsingWarning();
5410 return;
5411 }
5412 completionHandler(policyAction);
5413
5414 }, shouldExpectSafeBrowsingResult, shouldExpectAppBoundDomainResult));
5415 if (shouldExpectSafeBrowsingResult == ShouldExpectSafeBrowsingResult::Yes)
5416 beginSafeBrowsingCheck(request.url(), frame.isMainFrame(), listener);
5417#if ENABLE(APP_BOUND_DOMAINS)
5418 bool shouldSendSecurityOriginData = !frame.isMainFrame() && shouldTreatURLProtocolAsAppBound(request.url());
5419 auto host = shouldSendSecurityOriginData ? frameInfo.securityOrigin.host : request.url().host();
5420 auto protocol = shouldSendSecurityOriginData ? frameInfo.securityOrigin.protocol : request.url().protocol();
5421 m_websiteDataStore->beginAppBoundDomainCheck(host.toString(), protocol.toString(), listener);
5422#endif
5423
5424#if ENABLE(RESOURCE_LOAD_STATISTICS)
5425 auto wasPotentiallyInitiatedByUser = navigation->isLoadedWithNavigationShared() || userInitiatedActivity;
5426 if (!sessionID().isEphemeral())
5427 logFrameNavigation(frame, URL(URL(), m_pageLoadState.url()), request, redirectResponse.url(), wasPotentiallyInitiatedByUser);
5428#endif
5429
5430 if (m_policyClient)
5431 m_policyClient->decidePolicyForNavigationAction(*this, &frame, WTFMove(navigationAction), originatingFrame, originalRequest, WTFMove(request), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5432 else {
5433#if HAVE(APP_SSO)
5434 if (m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision || m_shouldSuppressSOAuthorizationInAllNavigationPolicyDecision)
5435 navigationAction->unsetShouldPerformSOAuthorization();
5436#endif
5437
5438 m_navigationClient->decidePolicyForNavigationAction(*this, WTFMove(navigationAction), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5439 }
5440
5441 m_shouldSuppressAppLinksInNextNavigationPolicyDecision = false;
5442
5443#if HAVE(APP_SSO)
5444 m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision = false;
5445#endif
5446}
5447
5448WebPageProxy* WebPageProxy::nonEphemeralWebPageProxy()
5449{
5450 auto processPools = WebProcessPool::allProcessPools();
5451 if (processPools.isEmpty())
5452 return nullptr;
5453
5454 for (auto& webProcess : processPools[0]->processes()) {
5455 for (auto& page : webProcess->pages()) {
5456 if (page->sessionID().isEphemeral())
5457 continue;
5458 return page;
5459 }
5460 }
5461 return nullptr;
5462}
5463
5464#if ENABLE(RESOURCE_LOAD_STATISTICS)
5465void WebPageProxy::logFrameNavigation(const WebFrameProxy& frame, const URL& pageURL, const WebCore::ResourceRequest& request, const URL& redirectURL, bool wasPotentiallyInitiatedByUser)
5466{
5467 ASSERT(RunLoop::isMain());
5468
5469 auto sourceURL = redirectURL;
5470 bool isRedirect = !redirectURL.isNull();
5471 if (!isRedirect) {
5472 sourceURL = frame.url();
5473 if (sourceURL.isNull())
5474 sourceURL = pageURL;
5475 }
5476
5477 auto& targetURL = request.url();
5478
5479 if (!targetURL.isValid() || !pageURL.isValid())
5480 return;
5481
5482 auto targetHost = targetURL.host();
5483 auto mainFrameHost = pageURL.host();
5484
5485 if (targetHost.isEmpty() || mainFrameHost.isEmpty() || targetHost == sourceURL.host())
5486 return;
5487
5488 websiteDataStore().networkProcess().send(Messages::NetworkProcess::LogFrameNavigation(m_websiteDataStore->sessionID(), RegistrableDomain { targetURL }, RegistrableDomain { pageURL }, RegistrableDomain { sourceURL }, isRedirect, frame.isMainFrame(), MonotonicTime::now() - m_didFinishDocumentLoadForMainFrameTimestamp, wasPotentiallyInitiatedByUser), 0);
5489}
5490#endif
5491
5492void WebPageProxy::decidePolicyForNavigationActionSync(FrameIdentifier frameID, bool isMainFrame, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier,
5493 uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID,
5494 const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse,
5495 const UserData& userData, Messages::WebPageProxy::DecidePolicyForNavigationActionSync::DelayedReply&& reply)
5496{
5497 auto* frame = m_process->webFrame(frameID);
5498 if (!frame) {
5499 // This synchronous IPC message was processed before the asynchronous DidCreateMainFrame / DidCreateSubframe one so we do not know about this frameID yet.
5500 if (isMainFrame)
5501 didCreateMainFrame(frameID);
5502 else
5503 didCreateSubframe(frameID);
5504 }
5505
5506 decidePolicyForNavigationActionSyncShared(m_process.copyRef(), frameID, isMainFrame, WTFMove(frameInfo), identifier, navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, WTFMove(reply));
5507}
5508
5509void WebPageProxy::decidePolicyForNavigationActionSyncShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, bool isMainFrame, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, Messages::WebPageProxy::DecidePolicyForNavigationActionSync::DelayedReply&& reply)
5510{
5511 auto sender = PolicyDecisionSender::create(identifier, WTFMove(reply));
5512
5513 auto* frame = process->webFrame(frameID);
5514 MESSAGE_CHECK(process, frame);
5515
5516 decidePolicyForNavigationAction(WTFMove(process), *frame, WTFMove(frameInfo), navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, sender.copyRef());
5517
5518 // If the client did not respond synchronously, proceed with the load.
5519 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Use, navigationID, std::nullopt, std::nullopt });
5520}
5521
5522void WebPageProxy::decidePolicyForNewWindowAction(FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, NavigationActionData&& navigationActionData, ResourceRequest&& request, const String& frameName, uint64_t listenerID, const UserData& userData)
5523{
5524 PageClientProtector protector(pageClient());
5525
5526 WebFrameProxy* frame = m_process->webFrame(frameID);
5527 MESSAGE_CHECK(m_process, frame);
5528 MESSAGE_CHECK_URL(m_process, request.url());
5529
5530 RefPtr<API::FrameInfo> sourceFrameInfo;
5531 if (frame)
5532 sourceFrameInfo = API::FrameInfo::create(WTFMove(frameInfo), this);
5533
5534 auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
5535 bool shouldOpenAppLinks = m_mainFrame && m_mainFrame->url().host() != request.url().host();
5536 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), nullptr, frameName, ResourceRequest(request), URL { }, shouldOpenAppLinks, WTFMove(userInitiatedActivity));
5537
5538 auto listener = makeRef(frame->setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), identifier, listenerID, frameID, navigationAction] (PolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain) mutable {
5539 // FIXME: Assert the API::WebsitePolicies* is nullptr here once clients of WKFramePolicyListenerUseWithPolicies go away.
5540 RELEASE_ASSERT(processSwapRequestedByClient == ProcessSwapRequestedByClient::No);
5541 ASSERT_UNUSED(safeBrowsingWarning, !safeBrowsingWarning);
5542
5543 auto sender = PolicyDecisionSender::create(identifier, [this, protectedThis = WTFMove(protectedThis), frameID, listenerID] (const auto& policyDecision) {
5544 send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, policyDecision, createNetworkExtensionsSandboxExtensions(m_process)));
5545 });
5546
5547 receivedPolicyDecision(policyAction, nullptr, nullptr, WTFMove(navigationAction), WTFMove(sender));
5548 }, ShouldExpectSafeBrowsingResult::No, ShouldExpectAppBoundDomainResult::No));
5549
5550 if (m_policyClient)
5551 m_policyClient->decidePolicyForNewWindowAction(*this, *frame, navigationAction.get(), request, frameName, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
5552 else
5553 m_navigationClient->decidePolicyForNavigationAction(*this, navigationAction.get(), WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
5554}
5555
5556void WebPageProxy::decidePolicyForResponse(FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier,
5557 uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, const String& downloadAttribute, uint64_t listenerID, const UserData& userData)
5558{
5559 decidePolicyForResponseShared(m_process.copyRef(), m_webPageID, frameID, WTFMove(frameInfo), identifier, navigationID, response, request, canShowMIMEType, downloadAttribute, listenerID, userData);
5560}
5561
5562void WebPageProxy::decidePolicyForResponseShared(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier,
5563 uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, const String& downloadAttribute, uint64_t listenerID, const UserData& userData)
5564{
5565 PageClientProtector protector(pageClient());
5566
5567 m_decidePolicyForResponseRequest = request;
5568
5569 WebFrameProxy* frame = process->webFrame(frameID);
5570 MESSAGE_CHECK(process, frame);
5571 MESSAGE_CHECK_URL(process, request.url());
5572 MESSAGE_CHECK_URL(process, response.url());
5573 RefPtr<API::Navigation> navigation = navigationID ? m_navigationState->navigation(navigationID) : nullptr;
5574 auto navigationResponse = API::NavigationResponse::create(API::FrameInfo::create(WTFMove(frameInfo), this).get(), request, response, canShowMIMEType, downloadAttribute);
5575
5576 auto listener = makeRef(frame->setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), webPageID, frameID, identifier, listenerID, navigation = WTFMove(navigation),
5577 process, navigationResponse] (PolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain) mutable {
5578 // FIXME: Assert the API::WebsitePolicies* is nullptr here once clients of WKFramePolicyListenerUseWithPolicies go away.
5579 RELEASE_ASSERT(processSwapRequestedByClient == ProcessSwapRequestedByClient::No);
5580 ASSERT_UNUSED(safeBrowsingWarning, !safeBrowsingWarning);
5581
5582 auto sender = PolicyDecisionSender::create(identifier, [webPageID, frameID, listenerID, process = WTFMove(process)] (const auto& policyDecision) {
5583 process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, policyDecision, createNetworkExtensionsSandboxExtensions(process)), webPageID);
5584 });
5585
5586 receivedPolicyDecision(policyAction, navigation.get(), nullptr, WTFMove(navigationResponse), WTFMove(sender));
5587 }, ShouldExpectSafeBrowsingResult::No, ShouldExpectAppBoundDomainResult::No));
5588 if (m_policyClient)
5589 m_policyClient->decidePolicyForResponse(*this, *frame, response, request, canShowMIMEType, WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5590 else
5591 m_navigationClient->decidePolicyForNavigationResponse(*this, WTFMove(navigationResponse), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5592}
5593
5594void WebPageProxy::unableToImplementPolicy(FrameIdentifier frameID, const ResourceError& error, const UserData& userData)
5595{
5596 PageClientProtector protector(pageClient());
5597
5598 WebFrameProxy* frame = m_process->webFrame(frameID);
5599 MESSAGE_CHECK(m_process, frame);
5600
5601 if (!m_policyClient)
5602 return;
5603 m_policyClient->unableToImplementPolicy(*this, *frame, error, m_process->transformHandlesToObjects(userData.object()).get());
5604}
5605
5606// FormClient
5607
5608void WebPageProxy::willSubmitForm(FrameIdentifier frameID, FrameIdentifier sourceFrameID, const Vector<std::pair<String, String>>& textFieldValues, uint64_t listenerID, const UserData& userData)
5609{
5610 WebFrameProxy* frame = m_process->webFrame(frameID);
5611 MESSAGE_CHECK(m_process, frame);
5612
5613 WebFrameProxy* sourceFrame = m_process->webFrame(sourceFrameID);
5614 MESSAGE_CHECK(m_process, sourceFrame);
5615
5616 for (auto& pair : textFieldValues)
5617 MESSAGE_CHECK(m_process, API::Dictionary::MapType::isValidKey(pair.first));
5618
5619 m_formClient->willSubmitForm(*this, *frame, *sourceFrame, textFieldValues, m_process->transformHandlesToObjects(userData.object()).get(), [this, protectedThis = makeRef(*this), frameID, listenerID]() {
5620 send(Messages::WebPage::ContinueWillSubmitForm(frameID, listenerID));
5621 });
5622}
5623
5624void WebPageProxy::contentRuleListNotification(URL&& url, ContentRuleListResults&& results)
5625{
5626 m_navigationClient->contentRuleListNotification(*this, WTFMove(url), WTFMove(results));
5627}
5628
5629void WebPageProxy::didNavigateWithNavigationData(const WebNavigationDataStore& store, FrameIdentifier frameID)
5630{
5631 didNavigateWithNavigationDataShared(m_process.copyRef(), store, frameID);
5632}
5633
5634void WebPageProxy::didNavigateWithNavigationDataShared(Ref<WebProcessProxy>&& process, const WebNavigationDataStore& store, FrameIdentifier frameID)
5635{
5636 WEBPAGEPROXY_RELEASE_LOG(Loading, "didNavigateWithNavigationDataShared:");
5637
5638 PageClientProtector protector(pageClient());
5639
5640 WebFrameProxy* frame = process->webFrame(frameID);
5641 MESSAGE_CHECK(process, frame);
5642 MESSAGE_CHECK(process, frame->page() == this);
5643
5644 if (frame->isMainFrame())
5645 m_historyClient->didNavigateWithNavigationData(*this, store);
5646 process->processPool().historyClient().didNavigateWithNavigationData(process->processPool(), *this, store, *frame);
5647}
5648
5649void WebPageProxy::didPerformClientRedirect(const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
5650{
5651 didPerformClientRedirectShared(m_process.copyRef(), sourceURLString, destinationURLString, frameID);
5652}
5653
5654void WebPageProxy::didPerformClientRedirectShared(Ref<WebProcessProxy>&& process, const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
5655{
5656 WEBPAGEPROXY_RELEASE_LOG(Loading, "didPerformClientRedirectShared: frameID=%" PRIu64, frameID.toUInt64());
5657
5658 PageClientProtector protector(pageClient());
5659
5660 if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
5661 return;
5662
5663 WebFrameProxy* frame = process->webFrame(frameID);
5664 MESSAGE_CHECK(process, frame);
5665 MESSAGE_CHECK(process, frame->page() == this);
5666 MESSAGE_CHECK_URL(process, sourceURLString);
5667 MESSAGE_CHECK_URL(process, destinationURLString);
5668
5669 if (frame->isMainFrame()) {
5670 m_historyClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString);
5671 m_navigationClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString);
5672 }
5673 process->processPool().historyClient().didPerformClientRedirect(process->processPool(), *this, sourceURLString, destinationURLString, *frame);
5674}
5675
5676void WebPageProxy::didPerformServerRedirect(const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
5677{
5678 didPerformServerRedirectShared(m_process.copyRef(), sourceURLString, destinationURLString, frameID);
5679}
5680
5681void WebPageProxy::didPerformServerRedirectShared(Ref<WebProcessProxy>&& process, const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
5682{
5683 WEBPAGEPROXY_RELEASE_LOG(Loading, "didPerformServerRedirect:");
5684
5685 PageClientProtector protector(pageClient());
5686
5687 if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
5688 return;
5689
5690 WebFrameProxy* frame = process->webFrame(frameID);
5691 MESSAGE_CHECK(process, frame);
5692 MESSAGE_CHECK(process, frame->page() == this);
5693
5694 MESSAGE_CHECK_URL(process, sourceURLString);
5695 MESSAGE_CHECK_URL(process, destinationURLString);
5696
5697 if (frame->isMainFrame())
5698 m_historyClient->didPerformServerRedirect(*this, sourceURLString, destinationURLString);
5699 process->processPool().historyClient().didPerformServerRedirect(process->processPool(), *this, sourceURLString, destinationURLString, *frame);
5700}
5701
5702void WebPageProxy::didUpdateHistoryTitle(const String& title, const String& url, FrameIdentifier frameID)
5703{
5704 PageClientProtector protector(pageClient());
5705
5706 WebFrameProxy* frame = m_process->webFrame(frameID);
5707 MESSAGE_CHECK(m_process, frame);
5708 MESSAGE_CHECK(m_process, frame->page() == this);
5709
5710 MESSAGE_CHECK_URL(m_process, url);
5711
5712 if (frame->isMainFrame())
5713 m_historyClient->didUpdateHistoryTitle(*this, title, url);
5714 process().processPool().historyClient().didUpdateHistoryTitle(process().processPool(), *this, title, url, *frame);
5715}
5716
5717// UIClient
5718
5719using NewPageCallback = CompletionHandler<void(RefPtr<WebPageProxy>&&)>;
5720using UIClientCallback = Function<void(Ref<API::NavigationAction>&&, NewPageCallback&&)>;
5721static void trySOAuthorization(Ref<API::NavigationAction>&& navigationAction, WebPageProxy& page, NewPageCallback&& newPageCallback, UIClientCallback&& uiClientCallback)
5722{
5723#if HAVE(APP_SSO)
5724 page.websiteDataStore().soAuthorizationCoordinator().tryAuthorize(WTFMove(navigationAction), page, WTFMove(newPageCallback), WTFMove(uiClientCallback));
5725#else
5726 uiClientCallback(WTFMove(navigationAction), WTFMove(newPageCallback));
5727#endif
5728}
5729
5730void WebPageProxy::createNewPage(FrameInfoData&& originatingFrameInfoData, WebPageProxyIdentifier originatingPageID, ResourceRequest&& request, WindowFeatures&& windowFeatures, NavigationActionData&& navigationActionData, Messages::WebPageProxy::CreateNewPage::DelayedReply&& reply)
5731{
5732 MESSAGE_CHECK(m_process, originatingFrameInfoData.frameID);
5733 MESSAGE_CHECK(m_process, m_process->webFrame(*originatingFrameInfoData.frameID));
5734
5735 auto* originatingPage = m_process->webPage(originatingPageID);
5736 auto originatingFrameInfo = API::FrameInfo::create(WTFMove(originatingFrameInfoData), originatingPage);
5737 auto mainFrameURL = m_mainFrame ? m_mainFrame->url() : URL();
5738 auto completionHandler = [this, protectedThis = makeRef(*this), mainFrameURL, request, reply = WTFMove(reply), privateClickMeasurement = navigationActionData.privateClickMeasurement] (RefPtr<WebPageProxy> newPage) mutable {
5739 if (!newPage) {
5740 reply(std::nullopt, std::nullopt);
5741 return;
5742 }
5743
5744 newPage->setOpenedByDOM();
5745
5746 reply(newPage->webPageID(), newPage->creationParameters(m_process, *newPage->drawingArea()));
5747
5748 newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = mainFrameURL.host() == request.url().host();
5749
5750 newPage->m_privateClickMeasurement = privateClickMeasurement;
5751#if HAVE(APP_SSO)
5752 newPage->m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision = true;
5753#endif
5754 };
5755
5756 RefPtr<API::UserInitiatedAction> userInitiatedActivity;
5757
5758 // WebKit cancels the original gesture to open the BBC radio player so
5759 // we can call the Storage Access API first. When we re-initiate the open,
5760 // we should make sure the client knows that this was user initiated so it
5761 // does not block the popup.
5762 if (request.url().string() == Quirks::staticRadioPlayerURLString())
5763 userInitiatedActivity = API::UserInitiatedAction::create();
5764 else
5765 userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
5766
5767 bool shouldOpenAppLinks = originatingFrameInfo->request().url().host() != request.url().host();
5768 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), originatingFrameInfo.ptr(), nullptr, std::nullopt, WTFMove(request), URL(), shouldOpenAppLinks, WTFMove(userInitiatedActivity));
5769
5770 trySOAuthorization(WTFMove(navigationAction), *this, WTFMove(completionHandler), [this, protectedThis = makeRef(*this), windowFeatures = WTFMove(windowFeatures)] (Ref<API::NavigationAction>&& navigationAction, CompletionHandler<void(RefPtr<WebPageProxy>&&)>&& completionHandler) mutable {
5771 m_uiClient->createNewPage(*this, WTFMove(windowFeatures), WTFMove(navigationAction), WTFMove(completionHandler));
5772 });
5773}
5774
5775void WebPageProxy::showPage()
5776{
5777 m_uiClient->showPage(this);
5778}
5779
5780void WebPageProxy::exitFullscreenImmediately()
5781{
5782#if ENABLE(FULLSCREEN_API)
5783 if (fullScreenManager())
5784 fullScreenManager()->close();
5785#endif
5786
5787#if ENABLE(VIDEO_PRESENTATION_MODE)
5788 if (videoFullscreenManager())
5789 videoFullscreenManager()->requestHideAndExitFullscreen();
5790#endif
5791}
5792
5793void WebPageProxy::fullscreenMayReturnToInline()
5794{
5795 m_uiClient->fullscreenMayReturnToInline(this);
5796}
5797
5798void WebPageProxy::didEnterFullscreen()
5799{
5800 m_uiClient->didEnterFullscreen(this);
5801}
5802
5803void WebPageProxy::didExitFullscreen()
5804{
5805 m_uiClient->didExitFullscreen(this);
5806}
5807
5808void WebPageProxy::closePage()
5809{
5810 if (isClosed())
5811 return;
5812
5813 WEBPAGEPROXY_RELEASE_LOG(Process, "closePage:");
5814 pageClient().clearAllEditCommands();
5815 m_uiClient->close(this);
5816}
5817
5818void WebPageProxy::runModalJavaScriptDialog(RefPtr<WebFrameProxy>&& frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void(WebPageProxy&, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&&)>&& runDialogCallback)
5819{
5820 pageClient().runModalJavaScriptDialog([weakThis = makeWeakPtr(*this), frameInfo = WTFMove(frameInfo), frame = WTFMove(frame), message, runDialogCallback = WTFMove(runDialogCallback)]() mutable {
5821 auto protectedThis = makeRefPtr(weakThis.get());
5822 if (!protectedThis)
5823 return;
5824
5825 protectedThis->m_isRunningModalJavaScriptDialog = true;
5826 runDialogCallback(*protectedThis, frame.get(), WTFMove(frameInfo), message, [weakThis = WTFMove(weakThis)]() mutable {
5827 if (auto protectedThis = makeRefPtr(weakThis.get()))
5828 protectedThis->m_isRunningModalJavaScriptDialog = false;
5829 });
5830 });
5831}
5832
5833void WebPageProxy::runJavaScriptAlert(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply&& reply)
5834{
5835 auto frame = makeRefPtr(m_process->webFrame(frameID));
5836 MESSAGE_CHECK(m_process, frame);
5837
5838 exitFullscreenImmediately();
5839
5840 // Since runJavaScriptAlert() can spin a nested run loop we need to turn off the responsiveness timer.
5841 m_process->stopResponsivenessTimer();
5842
5843 if (m_controlledByAutomation) {
5844 if (auto* automationSession = process().processPool().automationSession())
5845 automationSession->willShowJavaScriptDialog(*this);
5846 }
5847
5848 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
5849 page.m_uiClient->runJavaScriptAlert(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)]() mutable {
5850 reply();
5851 completion();
5852 });
5853 });
5854}
5855
5856void WebPageProxy::runJavaScriptConfirm(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, Messages::WebPageProxy::RunJavaScriptConfirm::DelayedReply&& reply)
5857{
5858 auto frame = makeRefPtr(m_process->webFrame(frameID));
5859 MESSAGE_CHECK(m_process, frame);
5860
5861 exitFullscreenImmediately();
5862
5863 // Since runJavaScriptConfirm() can spin a nested run loop we need to turn off the responsiveness timer.
5864 m_process->stopResponsivenessTimer();
5865
5866 if (m_controlledByAutomation) {
5867 if (auto* automationSession = process().processPool().automationSession())
5868 automationSession->willShowJavaScriptDialog(*this);
5869 }
5870
5871 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
5872 page.m_uiClient->runJavaScriptConfirm(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](bool result) mutable {
5873 reply(result);
5874 completion();
5875 });
5876 });
5877}
5878
5879void WebPageProxy::runJavaScriptPrompt(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, const String& defaultValue, Messages::WebPageProxy::RunJavaScriptPrompt::DelayedReply&& reply)
5880{
5881 auto frame = makeRefPtr(m_process->webFrame(frameID));
5882 MESSAGE_CHECK(m_process, frame);
5883
5884 exitFullscreenImmediately();
5885
5886 // Since runJavaScriptPrompt() can spin a nested run loop we need to turn off the responsiveness timer.
5887 m_process->stopResponsivenessTimer();
5888
5889 if (m_controlledByAutomation) {
5890 if (auto* automationSession = process().processPool().automationSession())
5891 automationSession->willShowJavaScriptDialog(*this);
5892 }
5893
5894 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply), defaultValue](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
5895 page.m_uiClient->runJavaScriptPrompt(page, message, defaultValue, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](auto& result) mutable {
5896 reply(result);
5897 completion();
5898 });
5899 });
5900}
5901
5902void WebPageProxy::setStatusText(const String& text)
5903{
5904 m_uiClient->setStatusText(this, text);
5905}
5906
5907void WebPageProxy::mouseDidMoveOverElement(WebHitTestResultData&& hitTestResultData, uint32_t opaqueModifiers, UserData&& userData)
5908{
5909 m_lastMouseMoveHitTestResult = API::HitTestResult::create(hitTestResultData);
5910 auto modifiers = OptionSet<WebEvent::Modifier>::fromRaw(opaqueModifiers);
5911 m_uiClient->mouseDidMoveOverElement(*this, hitTestResultData, modifiers, m_process->transformHandlesToObjects(userData.object()).get());
5912 setToolTip(hitTestResultData.toolTipText);
5913}
5914
5915#if ENABLE(NETSCAPE_PLUGIN_API)
5916void WebPageProxy::unavailablePluginButtonClicked(uint32_t opaquePluginUnavailabilityReason, const String& mimeType, const String& pluginURLString, const String& pluginspageAttributeURLString, const String& frameURLString, const String& pageURLString)
5917{
5918 MESSAGE_CHECK_URL(m_process, pluginURLString);
5919 MESSAGE_CHECK_URL(m_process, pluginspageAttributeURLString);
5920 MESSAGE_CHECK_URL(m_process, frameURLString);
5921 MESSAGE_CHECK_URL(m_process, pageURLString);
5922
5923 String newMimeType = mimeType;
5924 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString));
5925 auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, mimeType, pageURLString, pluginspageAttributeURLString, pluginURLString);
5926
5927 WKPluginUnavailabilityReason pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginMissing;
5928 switch (static_cast<RenderEmbeddedObject::PluginUnavailabilityReason>(opaquePluginUnavailabilityReason)) {
5929 case RenderEmbeddedObject::PluginMissing:
5930 pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginMissing;
5931 break;
5932 case RenderEmbeddedObject::InsecurePluginVersion:
5933 pluginUnavailabilityReason = kWKPluginUnavailabilityReasonInsecurePluginVersion;
5934 break;
5935 case RenderEmbeddedObject::PluginCrashed:
5936 pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginCrashed;
5937 break;
5938 case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy:
5939 case RenderEmbeddedObject::UnsupportedPlugin:
5940 case RenderEmbeddedObject::PluginTooSmall:
5941 ASSERT_NOT_REACHED();
5942 }
5943
5944 m_uiClient->unavailablePluginButtonClicked(*this, pluginUnavailabilityReason, pluginInformation.get());
5945}
5946#endif // ENABLE(NETSCAPE_PLUGIN_API)
5947
5948#if ENABLE(WEBGL)
5949void WebPageProxy::webGLPolicyForURL(URL&& url, Messages::WebPageProxy::WebGLPolicyForURL::DelayedReply&& reply)
5950{
5951 m_navigationClient->webGLLoadPolicy(*this, url, WTFMove(reply));
5952}
5953
5954void WebPageProxy::resolveWebGLPolicyForURL(URL&& url, Messages::WebPageProxy::ResolveWebGLPolicyForURL::DelayedReply&& reply)
5955{
5956 m_navigationClient->resolveWebGLLoadPolicy(*this, url, WTFMove(reply));
5957}
5958#endif // ENABLE(WEBGL)
5959
5960void WebPageProxy::setToolbarsAreVisible(bool toolbarsAreVisible)
5961{
5962 m_uiClient->setToolbarsAreVisible(*this, toolbarsAreVisible);
5963}
5964
5965void WebPageProxy::getToolbarsAreVisible(Messages::WebPageProxy::GetToolbarsAreVisible::DelayedReply&& reply)
5966{
5967 m_uiClient->toolbarsAreVisible(*this, WTFMove(reply));
5968}
5969
5970void WebPageProxy::setMenuBarIsVisible(bool menuBarIsVisible)
5971{
5972 m_uiClient->setMenuBarIsVisible(*this, menuBarIsVisible);
5973}
5974
5975void WebPageProxy::getMenuBarIsVisible(Messages::WebPageProxy::GetMenuBarIsVisible::DelayedReply&& reply)
5976{
5977 m_uiClient->menuBarIsVisible(*this, WTFMove(reply));
5978}
5979
5980void WebPageProxy::setStatusBarIsVisible(bool statusBarIsVisible)
5981{
5982 m_uiClient->setStatusBarIsVisible(*this, statusBarIsVisible);
5983}
5984
5985void WebPageProxy::getStatusBarIsVisible(Messages::WebPageProxy::GetStatusBarIsVisible::DelayedReply&& reply)
5986{
5987 m_uiClient->statusBarIsVisible(*this, WTFMove(reply));
5988}
5989
5990void WebPageProxy::setIsResizable(bool isResizable)
5991{
5992 m_uiClient->setIsResizable(*this, isResizable);
5993}
5994
5995void WebPageProxy::setWindowFrame(const FloatRect& newWindowFrame)
5996{
5997 m_uiClient->setWindowFrame(*this, pageClient().convertToDeviceSpace(newWindowFrame));
5998}
5999
6000void WebPageProxy::getWindowFrame(Messages::WebPageProxy::GetWindowFrame::DelayedReply&& reply)
6001{
6002 m_uiClient->windowFrame(*this, [this, protectedThis = makeRef(*this), reply = WTFMove(reply)] (FloatRect frame) mutable {
6003 reply(pageClient().convertToUserSpace(frame));
6004 });
6005}
6006
6007void WebPageProxy::getWindowFrameWithCallback(Function<void(FloatRect)>&& completionHandler)
6008{
6009 m_uiClient->windowFrame(*this, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (FloatRect frame) {
6010 completionHandler(pageClient().convertToUserSpace(frame));
6011 });
6012}
6013
6014void WebPageProxy::screenToRootView(const IntPoint& screenPoint, Messages::WebPageProxy::ScreenToRootView::DelayedReply&& reply)
6015{
6016 reply(pageClient().screenToRootView(screenPoint));
6017}
6018
6019void WebPageProxy::rootViewToScreen(const IntRect& viewRect, Messages::WebPageProxy::RootViewToScreen::DelayedReply&& reply)
6020{
6021 reply(pageClient().rootViewToScreen(viewRect));
6022}
6023
6024IntRect WebPageProxy::syncRootViewToScreen(const IntRect& viewRect)
6025{
6026 return pageClient().rootViewToScreen(viewRect);
6027}
6028
6029void WebPageProxy::accessibilityScreenToRootView(const IntPoint& screenPoint, CompletionHandler<void(IntPoint)>&& completionHandler)
6030{
6031 completionHandler(pageClient().accessibilityScreenToRootView(screenPoint));
6032}
6033
6034void WebPageProxy::rootViewToAccessibilityScreen(const IntRect& viewRect, CompletionHandler<void(IntRect)>&& completionHandler)
6035{
6036 completionHandler(pageClient().rootViewToAccessibilityScreen(viewRect));
6037}
6038
6039void WebPageProxy::runBeforeUnloadConfirmPanel(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply&& reply)
6040{
6041 WebFrameProxy* frame = m_process->webFrame(frameID);
6042 MESSAGE_CHECK(m_process, frame);
6043
6044 // Per §18 User Prompts in the WebDriver spec, "User prompts that are spawned from beforeunload
6045 // event handlers, are dismissed implicitly upon navigation or close window, regardless of the
6046 // defined user prompt handler." So, always allow the unload to proceed if the page is being automated.
6047 if (m_controlledByAutomation) {
6048 if (!!process().processPool().automationSession()) {
6049 reply(true);
6050 return;
6051 }
6052 }
6053
6054 // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer and the tryClose timer.
6055 m_process->stopResponsivenessTimer();
6056 bool shouldResumeTimerAfterPrompt = m_tryCloseTimeoutTimer.isActive();
6057 m_tryCloseTimeoutTimer.stop();
6058 m_uiClient->runBeforeUnloadConfirmPanel(*this, message, frame, WTFMove(frameInfo),
6059 [this, weakThis = makeWeakPtr(*this), completionHandler = WTFMove(reply), shouldResumeTimerAfterPrompt](bool shouldClose) mutable {
6060 if (weakThis && shouldResumeTimerAfterPrompt)
6061 m_tryCloseTimeoutTimer.startOneShot(tryCloseTimeoutDelay);
6062 completionHandler(shouldClose);
6063 });
6064}
6065
6066void WebPageProxy::didChangeViewportProperties(const ViewportAttributes& attr)
6067{
6068 pageClient().didChangeViewportProperties(attr);
6069}
6070
6071void WebPageProxy::pageDidScroll(const WebCore::IntPoint& scrollPosition)
6072{
6073 m_uiClient->pageDidScroll(this);
6074
6075 pageClient().pageDidScroll(scrollPosition);
6076
6077#if PLATFORM(IOS_FAMILY)
6078 // Do not hide the validation message if the scrolling was caused by the keyboard showing up.
6079 if (m_isKeyboardAnimatingIn)
6080 return;
6081#endif
6082
6083#if !PLATFORM(IOS_FAMILY)
6084 closeOverlayedViews();
6085#endif
6086}
6087
6088void WebPageProxy::runOpenPanel(FrameIdentifier frameID, FrameInfoData&& frameInfo, const FileChooserSettings& settings)
6089{
6090 if (m_openPanelResultListener) {
6091 m_openPanelResultListener->invalidate();
6092 m_openPanelResultListener = nullptr;
6093 }
6094
6095 WebFrameProxy* frame = m_process->webFrame(frameID);
6096 MESSAGE_CHECK(m_process, frame);
6097
6098 Ref<API::OpenPanelParameters> parameters = API::OpenPanelParameters::create(settings);
6099 m_openPanelResultListener = WebOpenPanelResultListenerProxy::create(this);
6100
6101 if (m_controlledByAutomation) {
6102 if (auto* automationSession = process().processPool().automationSession())
6103 automationSession->handleRunOpenPanel(*this, *frame, parameters.get(), *m_openPanelResultListener);
6104
6105 // Don't show a file chooser, since automation will be unable to interact with it.
6106 return;
6107 }
6108
6109 // Since runOpenPanel() can spin a nested run loop we need to turn off the responsiveness timer.
6110 m_process->stopResponsivenessTimer();
6111
6112 const auto frameInfoForPageClient = frameInfo;
6113
6114 if (!m_uiClient->runOpenPanel(*this, frame, WTFMove(frameInfo), parameters.ptr(), m_openPanelResultListener.get())) {
6115 if (!pageClient().handleRunOpenPanel(this, frame, frameInfoForPageClient, parameters.ptr(), m_openPanelResultListener.get()))
6116 didCancelForOpenPanel();
6117 }
6118}
6119
6120void WebPageProxy::showShareSheet(const ShareDataWithParsedURL& shareData, CompletionHandler<void(bool)>&& completionHandler)
6121{
6122 MESSAGE_CHECK(m_process, !shareData.url || shareData.url->protocolIsInHTTPFamily() || shareData.url->protocolIsData());
6123 MESSAGE_CHECK(m_process, shareData.files.isEmpty() || m_preferences->webShareFileAPIEnabled());
6124 pageClient().showShareSheet(shareData, WTFMove(completionHandler));
6125}
6126
6127void WebPageProxy::showContactPicker(const WebCore::ContactsRequestData& requestData, CompletionHandler<void(std::optional<Vector<WebCore::ContactInfo>>&&)>&& completionHandler)
6128{
6129 MESSAGE_CHECK(m_process, m_preferences->contactPickerAPIEnabled());
6130 pageClient().showContactPicker(requestData, WTFMove(completionHandler));
6131}
6132
6133void WebPageProxy::printFrame(FrameIdentifier frameID, const String& title, const WebCore::FloatSize& pdfFirstPageSize, CompletionHandler<void()>&& completionHandler)
6134{
6135 ASSERT(!m_isPerformingDOMPrintOperation);
6136 m_isPerformingDOMPrintOperation = true;
6137
6138 WebFrameProxy* frame = m_process->webFrame(frameID);
6139 MESSAGE_CHECK(m_process, frame);
6140
6141 frame->didChangeTitle(title);
6142
6143 m_uiClient->printFrame(*this, *frame, pdfFirstPageSize, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] () mutable {
6144 endPrinting(); // Send a message synchronously while m_isPerformingDOMPrintOperation is still true.
6145 m_isPerformingDOMPrintOperation = false;
6146 completionHandler();
6147 });
6148}
6149
6150void WebPageProxy::setMediaVolume(float volume)
6151{
6152 if (volume == m_mediaVolume)
6153 return;
6154
6155 m_mediaVolume = volume;
6156
6157 if (!hasRunningProcess())
6158 return;
6159
6160 send(Messages::WebPage::SetMediaVolume(volume));
6161}
6162
6163void WebPageProxy::setMuted(WebCore::MediaProducer::MutedStateFlags state, CompletionHandler<void()>&& completionHandler)
6164{
6165 m_mutedState = state;
6166
6167 if (!hasRunningProcess())
6168 return completionHandler();
6169
6170#if ENABLE(MEDIA_STREAM)
6171 bool hasMutedCaptureStreams = m_mediaState.containsAny(WebCore::MediaProducer::MutedCaptureMask);
6172 if (hasMutedCaptureStreams && !(state.containsAny(WebCore::MediaProducer::MediaStreamCaptureIsMuted)))
6173 WebProcessProxy::muteCaptureInPagesExcept(m_webPageID);
6174#endif
6175
6176 m_process->pageMutedStateChanged(m_webPageID, state);
6177
6178 sendWithAsyncReply(Messages::WebPage::SetMuted(state), WTFMove(completionHandler));
6179 activityStateDidChange({ ActivityState::IsAudible, ActivityState::IsCapturingMedia });
6180}
6181
6182void WebPageProxy::setMediaCaptureEnabled(bool enabled)
6183{
6184 m_mediaCaptureEnabled = enabled;
6185
6186 if (!hasRunningProcess())
6187 return;
6188
6189#if ENABLE(MEDIA_STREAM)
6190 UserMediaProcessManager::singleton().setCaptureEnabled(enabled);
6191#endif
6192}
6193
6194void WebPageProxy::stopMediaCapture(MediaProducer::MediaCaptureKind kind, CompletionHandler<void()>&& completionHandler)
6195{
6196 if (!hasRunningProcess())
6197 return completionHandler();
6198
6199#if ENABLE(MEDIA_STREAM)
6200 if (m_userMediaPermissionRequestManager)
6201 m_userMediaPermissionRequestManager->resetAccess();
6202 sendWithAsyncReply(Messages::WebPage::StopMediaCapture(kind), WTFMove(completionHandler));
6203#endif
6204}
6205
6206void WebPageProxy::requestMediaPlaybackState(CompletionHandler<void(MediaPlaybackState)>&& completionHandler)
6207{
6208 if (!hasRunningProcess()) {
6209 completionHandler({ });
6210 return;
6211 }
6212
6213 sendWithAsyncReply(Messages::WebPage::RequestMediaPlaybackState(), WTFMove(completionHandler));
6214}
6215
6216void WebPageProxy::pauseAllMediaPlayback(CompletionHandler<void()>&& completionHandler)
6217{
6218 if (!hasRunningProcess()) {
6219 completionHandler();
6220 return;
6221 }
6222
6223 sendWithAsyncReply(Messages::WebPage::PauseAllMediaPlayback(), WTFMove(completionHandler));
6224}
6225
6226void WebPageProxy::suspendAllMediaPlayback(CompletionHandler<void()>&& completionHandler)
6227{
6228 m_suspendMediaPlaybackCounter++;
6229 if (m_mediaPlaybackIsSuspended) {
6230 completionHandler();
6231 return;
6232 }
6233 m_mediaPlaybackIsSuspended = true;
6234
6235 if (!hasRunningProcess()) {
6236 completionHandler();
6237 return;
6238 }
6239
6240 sendWithAsyncReply(Messages::WebPage::SuspendAllMediaPlayback(), WTFMove(completionHandler));
6241}
6242
6243void WebPageProxy::resumeAllMediaPlayback(CompletionHandler<void()>&& completionHandler)
6244{
6245 if (m_suspendMediaPlaybackCounter > 0)
6246 m_suspendMediaPlaybackCounter--;
6247
6248 if (!m_mediaPlaybackIsSuspended || m_suspendMediaPlaybackCounter) {
6249 completionHandler();
6250 return;
6251 }
6252 m_mediaPlaybackIsSuspended = false;
6253
6254 if (!hasRunningProcess()) {
6255 completionHandler();
6256 return;
6257 }
6258
6259 sendWithAsyncReply(Messages::WebPage::ResumeAllMediaPlayback(), WTFMove(completionHandler));
6260}
6261
6262void WebPageProxy::setMayStartMediaWhenInWindow(bool mayStartMedia)
6263{
6264 if (mayStartMedia == m_mayStartMediaWhenInWindow)
6265 return;
6266
6267 m_mayStartMediaWhenInWindow = mayStartMedia;
6268
6269 if (!hasRunningProcess())
6270 return;
6271
6272 send(Messages::WebPage::SetMayStartMediaWhenInWindow(mayStartMedia));
6273}
6274
6275void WebPageProxy::handleDownloadRequest(DownloadProxy& download)
6276{
6277 pageClient().handleDownloadRequest(download);
6278}
6279
6280void WebPageProxy::resumeDownload(const API::Data& resumeData, const String& path, CompletionHandler<void(DownloadProxy*)>&& completionHandler)
6281{
6282 auto& download = process().processPool().resumeDownload(websiteDataStore(), this, resumeData, path, CallDownloadDidStart::Yes);
6283 download.setDestinationFilename(path);
6284 download.setDidStartCallback(WTFMove(completionHandler));
6285}
6286
6287void WebPageProxy::downloadRequest(WebCore::ResourceRequest&& request, CompletionHandler<void(DownloadProxy*)>&& completionHandler)
6288{
6289 auto& download = process().processPool().download(websiteDataStore(), this, request, { });
6290 download.setDidStartCallback(WTFMove(completionHandler));
6291}
6292
6293void WebPageProxy::didChangeContentSize(const IntSize& size)
6294{
6295 pageClient().didChangeContentSize(size);
6296}
6297
6298void WebPageProxy::didChangeIntrinsicContentSize(const IntSize& intrinsicContentSize)
6299{
6300#if USE(APPKIT)
6301 pageClient().intrinsicContentSizeDidChange(intrinsicContentSize);
6302#endif
6303}
6304
6305#if ENABLE(INPUT_TYPE_COLOR)
6306void WebPageProxy::showColorPicker(const WebCore::Color& initialColor, const IntRect& elementRect, Vector<WebCore::Color>&& suggestions)
6307{
6308 m_colorPicker = pageClient().createColorPicker(this, initialColor, elementRect, WTFMove(suggestions));
6309 m_colorPicker->showColorPicker(initialColor);
6310}
6311
6312void WebPageProxy::setColorPickerColor(const WebCore::Color& color)
6313{
6314 MESSAGE_CHECK(m_process, m_colorPicker);
6315
6316 m_colorPicker->setSelectedColor(color);
6317}
6318
6319void WebPageProxy::endColorPicker()
6320{
6321 if (auto colorPicker = std::exchange(m_colorPicker, nullptr))
6322 colorPicker->endPicker();
6323}
6324
6325void WebPageProxy::didChooseColor(const WebCore::Color& color)
6326{
6327 if (!hasRunningProcess())
6328 return;
6329
6330 send(Messages::WebPage::DidChooseColor(color));
6331}
6332
6333void WebPageProxy::didEndColorPicker()
6334{
6335 if (std::exchange(m_colorPicker, nullptr)) {
6336 if (!hasRunningProcess())
6337 return;
6338
6339 send(Messages::WebPage::DidEndColorPicker());
6340 }
6341
6342}
6343#endif
6344
6345#if ENABLE(DATALIST_ELEMENT)
6346
6347void WebPageProxy::showDataListSuggestions(WebCore::DataListSuggestionInformation&& info)
6348{
6349 if (!m_dataListSuggestionsDropdown)
6350 m_dataListSuggestionsDropdown = pageClient().createDataListSuggestionsDropdown(*this);
6351
6352 m_dataListSuggestionsDropdown->show(WTFMove(info));
6353}
6354
6355void WebPageProxy::handleKeydownInDataList(const String& key)
6356{
6357 if (!m_dataListSuggestionsDropdown)
6358 return;
6359
6360 m_dataListSuggestionsDropdown->handleKeydownWithIdentifier(key);
6361}
6362
6363void WebPageProxy::endDataListSuggestions()
6364{
6365 if (m_dataListSuggestionsDropdown)
6366 m_dataListSuggestionsDropdown->close();
6367}
6368
6369void WebPageProxy::didCloseSuggestions()
6370{
6371 if (!m_dataListSuggestionsDropdown)
6372 return;
6373
6374 m_dataListSuggestionsDropdown = nullptr;
6375 send(Messages::WebPage::DidCloseSuggestions());
6376}
6377
6378void WebPageProxy::didSelectOption(const String& selectedOption)
6379{
6380 if (!hasRunningProcess())
6381 return;
6382
6383 send(Messages::WebPage::DidSelectDataListOption(selectedOption));
6384}
6385
6386#endif
6387
6388#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
6389
6390void WebPageProxy::showDateTimePicker(WebCore::DateTimeChooserParameters&& params)
6391{
6392 if (!m_dateTimePicker)
6393 m_dateTimePicker = pageClient().createDateTimePicker(*this);
6394
6395 m_dateTimePicker->showDateTimePicker(WTFMove(params));
6396}
6397
6398void WebPageProxy::endDateTimePicker()
6399{
6400 if (!m_dateTimePicker)
6401 return;
6402
6403 m_dateTimePicker->endPicker();
6404}
6405
6406void WebPageProxy::didChooseDate(StringView date)
6407{
6408 if (!hasRunningProcess())
6409 return;
6410
6411 send(Messages::WebPage::DidChooseDate(date.toString()));
6412}
6413
6414void WebPageProxy::didEndDateTimePicker()
6415{
6416 m_dateTimePicker = nullptr;
6417 if (!hasRunningProcess())
6418 return;
6419
6420 send(Messages::WebPage::DidEndDateTimePicker());
6421}
6422
6423#endif
6424
6425WebInspectorUIProxy* WebPageProxy::inspector() const
6426{
6427 if (isClosed())
6428 return nullptr;
6429 return m_inspector.get();
6430}
6431
6432void WebPageProxy::resourceLoadDidSendRequest(ResourceLoadInfo&& loadInfo, WebCore::ResourceRequest&& request)
6433{
6434 if (m_resourceLoadClient)
6435 m_resourceLoadClient->didSendRequest(WTFMove(loadInfo), WTFMove(request));
6436}
6437
6438void WebPageProxy::resourceLoadDidPerformHTTPRedirection(ResourceLoadInfo&& loadInfo, WebCore::ResourceResponse&& response, WebCore::ResourceRequest&& request)
6439{
6440 if (m_resourceLoadClient)
6441 m_resourceLoadClient->didPerformHTTPRedirection(WTFMove(loadInfo), WTFMove(response), WTFMove(request));
6442}
6443
6444void WebPageProxy::resourceLoadDidReceiveChallenge(ResourceLoadInfo&& loadInfo, WebCore::AuthenticationChallenge&& challenge)
6445{
6446 if (m_resourceLoadClient)
6447 m_resourceLoadClient->didReceiveChallenge(WTFMove(loadInfo), WTFMove(challenge));
6448}
6449
6450void WebPageProxy::resourceLoadDidReceiveResponse(ResourceLoadInfo&& loadInfo, WebCore::ResourceResponse&& response)
6451{
6452 if (m_resourceLoadClient)
6453 m_resourceLoadClient->didReceiveResponse(WTFMove(loadInfo), WTFMove(response));
6454}
6455
6456void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, WebCore::ResourceResponse&& response, WebCore::ResourceError&& error)
6457{
6458 if (m_resourceLoadClient)
6459 m_resourceLoadClient->didCompleteWithError(WTFMove(loadInfo), WTFMove(response), WTFMove(error));
6460}
6461
6462#if ENABLE(FULLSCREEN_API)
6463WebFullScreenManagerProxy* WebPageProxy::fullScreenManager()
6464{
6465 return m_fullScreenManager.get();
6466}
6467
6468void WebPageProxy::setFullscreenClient(std::unique_ptr<API::FullscreenClient>&& client)
6469{
6470 if (!client) {
6471 m_fullscreenClient = makeUnique<API::FullscreenClient>();
6472 return;
6473 }
6474
6475 m_fullscreenClient = WTFMove(client);
6476}
6477#endif
6478
6479#if ENABLE(VIDEO_PRESENTATION_MODE)
6480PlaybackSessionManagerProxy* WebPageProxy::playbackSessionManager()
6481{
6482 return m_playbackSessionManager.get();
6483}
6484
6485VideoFullscreenManagerProxy* WebPageProxy::videoFullscreenManager()
6486{
6487 return m_videoFullscreenManager.get();
6488}
6489
6490void WebPageProxy::setMockVideoPresentationModeEnabled(bool enabled)
6491{
6492 m_mockVideoPresentationModeEnabled = enabled;
6493 if (m_videoFullscreenManager)
6494 m_videoFullscreenManager->setMockVideoPresentationModeEnabled(enabled);
6495}
6496#endif
6497
6498#if PLATFORM(IOS_FAMILY)
6499bool WebPageProxy::allowsMediaDocumentInlinePlayback() const
6500{
6501 return m_allowsMediaDocumentInlinePlayback;
6502}
6503
6504void WebPageProxy::setAllowsMediaDocumentInlinePlayback(bool allows)
6505{
6506 if (m_allowsMediaDocumentInlinePlayback == allows)
6507 return;
6508 m_allowsMediaDocumentInlinePlayback = allows;
6509
6510 send(Messages::WebPage::SetAllowsMediaDocumentInlinePlayback(allows));
6511}
6512#endif
6513
6514void WebPageProxy::setHasHadSelectionChangesFromUserInteraction(bool hasHadUserSelectionChanges)
6515{
6516 m_hasHadSelectionChangesFromUserInteraction = hasHadUserSelectionChanges;
6517}
6518
6519#if HAVE(TOUCH_BAR)
6520
6521void WebPageProxy::setIsTouchBarUpdateSupressedForHiddenContentEditable(bool ignoreTouchBarUpdate)
6522{
6523 m_isTouchBarUpdateSupressedForHiddenContentEditable = ignoreTouchBarUpdate;
6524}
6525
6526void WebPageProxy::setIsNeverRichlyEditableForTouchBar(bool isNeverRichlyEditable)
6527{
6528 m_isNeverRichlyEditableForTouchBar = isNeverRichlyEditable;
6529}
6530
6531#endif
6532
6533void WebPageProxy::requestDOMPasteAccess(const WebCore::IntRect& elementRect, const String& originIdentifier, CompletionHandler<void(WebCore::DOMPasteAccessResponse)>&& completionHandler)
6534{
6535 m_pageClient->requestDOMPasteAccess(elementRect, originIdentifier, WTFMove(completionHandler));
6536}
6537
6538// BackForwardList
6539
6540void WebPageProxy::backForwardAddItem(BackForwardListItemState&& itemState)
6541{
6542 auto item = WebBackForwardListItem::create(WTFMove(itemState), identifier());
6543 item->setResourceDirectoryURL(currentResourceDirectoryURL());
6544 m_backForwardList->addItem(WTFMove(item));
6545}
6546
6547void WebPageProxy::backForwardGoToItem(const BackForwardItemIdentifier& itemID, CompletionHandler<void(const WebBackForwardListCounts&)>&& completionHandler)
6548{
6549 // On process swap, we tell the previous process to ignore the load, which causes it so restore its current back forward item to its previous
6550 // value. Since the load is really going on in a new provisional process, we want to ignore such requests from the committed process.
6551 // Any real new load in the committed process would have cleared m_provisionalPage.
6552 if (m_provisionalPage)
6553 return completionHandler(m_backForwardList->counts());
6554
6555 backForwardGoToItemShared(m_process.copyRef(), itemID, WTFMove(completionHandler));
6556}
6557
6558void WebPageProxy::backForwardGoToItemShared(Ref<WebProcessProxy>&& process, const BackForwardItemIdentifier& itemID, CompletionHandler<void(const WebBackForwardListCounts&)>&& completionHandler)
6559{
6560 MESSAGE_CHECK_COMPLETION(m_process, !WebKit::isInspectorPage(*this), completionHandler(m_backForwardList->counts()));
6561
6562 auto* item = m_backForwardList->itemForID(itemID);
6563 if (!item)
6564 return completionHandler(m_backForwardList->counts());
6565
6566 m_backForwardList->goToItem(*item);
6567 completionHandler(m_backForwardList->counts());
6568}
6569
6570void WebPageProxy::backForwardItemAtIndex(int32_t index, CompletionHandler<void(std::optional<BackForwardItemIdentifier>&&)>&& completionHandler)
6571{
6572 if (auto* item = m_backForwardList->itemAtIndex(index))
6573 completionHandler(item->itemID());
6574 else
6575 completionHandler(std::nullopt);
6576}
6577
6578void WebPageProxy::backForwardListCounts(Messages::WebPageProxy::BackForwardListCountsDelayedReply&& completionHandler)
6579{
6580 completionHandler(m_backForwardList->counts());
6581}
6582
6583void WebPageProxy::compositionWasCanceled()
6584{
6585#if PLATFORM(COCOA)
6586 pageClient().notifyInputContextAboutDiscardedComposition();
6587#endif
6588}
6589
6590// Undo management
6591
6592void WebPageProxy::registerEditCommandForUndo(WebUndoStepID commandID, const String& label)
6593{
6594 registerEditCommand(WebEditCommandProxy::create(commandID, label, *this), UndoOrRedo::Undo);
6595}
6596
6597void WebPageProxy::registerInsertionUndoGrouping()
6598{
6599#if USE(INSERTION_UNDO_GROUPING)
6600 pageClient().registerInsertionUndoGrouping();
6601#endif
6602}
6603
6604void WebPageProxy::canUndoRedo(UndoOrRedo action, CompletionHandler<void(bool)>&& completionHandler)
6605{
6606 completionHandler(pageClient().canUndoRedo(action));
6607}
6608
6609void WebPageProxy::executeUndoRedo(UndoOrRedo action, CompletionHandler<void()>&& completionHandler)
6610{
6611 pageClient().executeUndoRedo(action);
6612 completionHandler();
6613}
6614
6615void WebPageProxy::clearAllEditCommands()
6616{
6617 pageClient().clearAllEditCommands();
6618}
6619
6620void WebPageProxy::didCountStringMatches(const String& string, uint32_t matchCount)
6621{
6622 m_findClient->didCountStringMatches(this, string, matchCount);
6623}
6624
6625void WebPageProxy::didGetImageForFindMatch(const ShareableBitmap::Handle& contentImageHandle, uint32_t matchIndex)
6626{
6627 auto bitmap = ShareableBitmap::create(contentImageHandle);
6628 if (!bitmap) {
6629 ASSERT_NOT_REACHED();
6630 return;
6631 }
6632 m_findMatchesClient->didGetImageForMatchResult(this, WebImage::create(bitmap.releaseNonNull()).ptr(), matchIndex);
6633}
6634
6635void WebPageProxy::setTextIndicator(const TextIndicatorData& indicatorData, uint64_t lifetime)
6636{
6637 // FIXME: Make TextIndicatorWindow a platform-independent presentational thing ("TextIndicatorPresentation"?).
6638#if PLATFORM(COCOA)
6639 pageClient().setTextIndicator(TextIndicator::create(indicatorData), static_cast<WebCore::TextIndicatorLifetime>(lifetime));
6640#else
6641 ASSERT_NOT_REACHED();
6642#endif
6643}
6644
6645void WebPageProxy::clearTextIndicator()
6646{
6647#if PLATFORM(COCOA)
6648 pageClient().clearTextIndicator(WebCore::TextIndicatorDismissalAnimation::FadeOut);
6649#else
6650 ASSERT_NOT_REACHED();
6651#endif
6652}
6653
6654void WebPageProxy::setTextIndicatorAnimationProgress(float progress)
6655{
6656#if PLATFORM(COCOA)
6657 pageClient().setTextIndicatorAnimationProgress(progress);
6658#else
6659 ASSERT_NOT_REACHED();
6660#endif
6661}
6662
6663void WebPageProxy::didFindString(const String& string, const Vector<WebCore::IntRect>& matchRects, uint32_t matchCount, int32_t matchIndex, bool didWrapAround)
6664{
6665 m_findClient->didFindString(this, string, matchRects, matchCount, matchIndex, didWrapAround);
6666}
6667
6668void WebPageProxy::didFindStringMatches(const String& string, const Vector<Vector<WebCore::IntRect>>& matchRects, int32_t firstIndexAfterSelection)
6669{
6670 m_findMatchesClient->didFindStringMatches(this, string, matchRects, firstIndexAfterSelection);
6671}
6672
6673void WebPageProxy::didFailToFindString(const String& string)
6674{
6675 m_findClient->didFailToFindString(this, string);
6676}
6677
6678bool WebPageProxy::sendMessage(UniqueRef<IPC::Encoder>&& encoder, OptionSet<IPC::SendOption> sendOptions, std::optional<std::pair<CompletionHandler<void(IPC::Decoder*)>, uint64_t>>&& asyncReplyInfo)
6679{
6680 return m_process->sendMessage(WTFMove(encoder), sendOptions, WTFMove(asyncReplyInfo));
6681}
6682
6683IPC::Connection* WebPageProxy::messageSenderConnection() const
6684{
6685 return m_process->hasConnection() ? m_process->connection() : nullptr;
6686}
6687
6688uint64_t WebPageProxy::messageSenderDestinationID() const
6689{
6690 return m_webPageID.toUInt64();
6691}
6692
6693void WebPageProxy::valueChangedForPopupMenu(WebPopupMenuProxy*, int32_t newSelectedIndex)
6694{
6695 send(Messages::WebPage::DidChangeSelectedIndexForActivePopupMenu(newSelectedIndex));
6696}
6697
6698void WebPageProxy::setTextFromItemForPopupMenu(WebPopupMenuProxy*, int32_t index)
6699{
6700 send(Messages::WebPage::SetTextForActivePopupMenu(index));
6701}
6702
6703bool WebPageProxy::isProcessingKeyboardEvents() const
6704{
6705 return !m_keyEventQueue.isEmpty();
6706}
6707
6708bool WebPageProxy::isProcessingMouseEvents() const
6709{
6710 return !m_mouseEventQueue.isEmpty();
6711}
6712
6713bool WebPageProxy::isProcessingWheelEvents() const
6714{
6715 return m_wheelEventCoalescer && m_wheelEventCoalescer->hasEventsBeingProcessed();
6716}
6717
6718NativeWebMouseEvent* WebPageProxy::currentlyProcessedMouseDownEvent()
6719{
6720 // <https://bugs.webkit.org/show_bug.cgi?id=57904> We need to keep track of the mouse down event in the case where we
6721 // display a popup menu for select elements. When the user changes the selected item, we fake a mouseup event by
6722 // using this stored mousedown event and changing the event type. This trickery happens when WebProcess handles
6723 // a mousedown event that runs the default handler for HTMLSelectElement, so the triggering mousedown must be the first event.
6724
6725 if (m_mouseEventQueue.isEmpty())
6726 return nullptr;
6727
6728 auto& event = m_mouseEventQueue.first();
6729 if (event.type() != WebEvent::Type::MouseDown)
6730 return nullptr;
6731
6732 return &event;
6733}
6734
6735void WebPageProxy::postMessageToInjectedBundle(const String& messageName, API::Object* messageBody)
6736{
6737 if (!hasRunningProcess()) {
6738 m_pendingInjectedBundleMessages.append(InjectedBundleMessage { messageName, messageBody });
6739 return;
6740 }
6741
6742 send(Messages::WebPage::PostInjectedBundleMessage(messageName, UserData(process().transformObjectsToHandles(messageBody).get())));
6743}
6744
6745#if PLATFORM(GTK)
6746void WebPageProxy::failedToShowPopupMenu()
6747{
6748 send(Messages::WebPage::FailedToShowPopupMenu());
6749}
6750#endif
6751
6752void WebPageProxy::showPopupMenu(const IntRect& rect, uint64_t textDirection, const Vector<WebPopupItem>& items, int32_t selectedIndex, const PlatformPopupMenuData& data)
6753{
6754 MESSAGE_CHECK(m_process, selectedIndex == -1 || static_cast<uint32_t>(selectedIndex) < items.size());
6755
6756 if (m_activePopupMenu) {
6757 m_activePopupMenu->hidePopupMenu();
6758 m_activePopupMenu->invalidate();
6759 m_activePopupMenu = nullptr;
6760 }
6761
6762 // If the page is controlled by automation, entering a nested run loop while the menu is open
6763 // can hang the page / WebDriver test. Since <option> elements are selected via a different
6764 // code path anyway, just don't show the native popup menu.
6765 if (auto* automationSession = process().processPool().automationSession()) {
6766 if (m_controlledByAutomation && automationSession->isSimulatingUserInteraction())
6767 return;
6768 }
6769
6770 m_activePopupMenu = pageClient().createPopupMenuProxy(*this);
6771
6772 if (!m_activePopupMenu)
6773 return;
6774
6775 // Since showPopupMenu() can spin a nested run loop we need to turn off the responsiveness timer.
6776 m_process->stopResponsivenessTimer();
6777
6778 // Showing a popup menu runs a nested runloop, which can handle messages that cause |this| to get closed.
6779 Ref<WebPageProxy> protect(*this);
6780 m_activePopupMenu->showPopupMenu(rect, static_cast<TextDirection>(textDirection), m_pageScaleFactor, items, data, selectedIndex);
6781}
6782
6783void WebPageProxy::hidePopupMenu()
6784{
6785 if (!m_activePopupMenu)
6786 return;
6787
6788 m_activePopupMenu->hidePopupMenu();
6789 m_activePopupMenu->invalidate();
6790 m_activePopupMenu = nullptr;
6791}
6792
6793#if ENABLE(CONTEXT_MENUS)
6794void WebPageProxy::showContextMenu(ContextMenuContextData&& contextMenuContextData, const UserData& userData)
6795{
6796 // Showing a context menu runs a nested runloop, which can handle messages that cause |this| to get closed.
6797 Ref<WebPageProxy> protect(*this);
6798
6799 // If the page is controlled by automation, entering a nested run loop while the menu is open
6800 // can hang the page / WebDriver test. Pretend to show and immediately dismiss the context menu.
6801 if (auto* automationSession = process().processPool().automationSession()) {
6802 if (m_controlledByAutomation && automationSession->isSimulatingUserInteraction()) {
6803 send(Messages::WebPage::ContextMenuHidden());
6804 return;
6805 }
6806 }
6807
6808 // Discard any enqueued mouse events that have been delivered to the UIProcess whilst the WebProcess is still processing the
6809 // MouseDown event that triggered this ShowContextMenu message. This can happen if we take too long to enter the nested runloop.
6810 discardQueuedMouseEvents();
6811
6812 m_activeContextMenuContextData = contextMenuContextData;
6813
6814 m_activeContextMenu = pageClient().createContextMenuProxy(*this, WTFMove(contextMenuContextData), userData);
6815
6816 m_activeContextMenu->show();
6817}
6818
6819void WebPageProxy::contextMenuItemSelected(const WebContextMenuItemData& item)
6820{
6821 // Application custom items don't need to round-trip through to WebCore in the WebProcess.
6822 if (item.action() >= ContextMenuItemBaseApplicationTag) {
6823 m_contextMenuClient->customContextMenuItemSelected(*this, item);
6824 return;
6825 }
6826
6827 struct DownloadInfo {
6828 String url;
6829 String suggestedFilename;
6830 };
6831 std::optional<DownloadInfo> downloadInfo;
6832
6833 switch (item.action()) {
6834#if PLATFORM(COCOA)
6835 case ContextMenuItemTagSmartCopyPaste:
6836 setSmartInsertDeleteEnabled(!isSmartInsertDeleteEnabled());
6837 return;
6838
6839 case ContextMenuItemTagSmartQuotes:
6840 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
6841 m_process->updateTextCheckerState();
6842 return;
6843
6844 case ContextMenuItemTagSmartDashes:
6845 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
6846 m_process->updateTextCheckerState();
6847 return;
6848
6849 case ContextMenuItemTagSmartLinks:
6850 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
6851 m_process->updateTextCheckerState();
6852 return;
6853
6854 case ContextMenuItemTagTextReplacement:
6855 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
6856 m_process->updateTextCheckerState();
6857 return;
6858
6859 case ContextMenuItemTagCorrectSpellingAutomatically:
6860 TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled);
6861 m_process->updateTextCheckerState();
6862 return;
6863
6864 case ContextMenuItemTagShowSubstitutions:
6865 TextChecker::toggleSubstitutionsPanelIsShowing();
6866 return;
6867#endif
6868
6869 case ContextMenuItemTagDownloadImageToDisk:
6870 downloadInfo = {{ m_activeContextMenuContextData.webHitTestResultData().absoluteImageURL, { } }};
6871 break;
6872
6873 case ContextMenuItemTagDownloadLinkToDisk: {
6874 auto& hitTestResult = m_activeContextMenuContextData.webHitTestResultData();
6875 downloadInfo = {{ hitTestResult.absoluteLinkURL, hitTestResult.linkSuggestedFilename }};
6876 break;
6877 }
6878
6879 case ContextMenuItemTagDownloadMediaToDisk:
6880 downloadInfo = {{ m_activeContextMenuContextData.webHitTestResultData().absoluteMediaURL, { } }};
6881 break;
6882
6883 case ContextMenuItemTagCheckSpellingWhileTyping:
6884 TextChecker::setContinuousSpellCheckingEnabled(!TextChecker::state().isContinuousSpellCheckingEnabled);
6885 m_process->updateTextCheckerState();
6886 return;
6887
6888 case ContextMenuItemTagCheckGrammarWithSpelling:
6889 TextChecker::setGrammarCheckingEnabled(!TextChecker::state().isGrammarCheckingEnabled);
6890 m_process->updateTextCheckerState();
6891 return;
6892
6893 case ContextMenuItemTagShowSpellingPanel:
6894 if (!TextChecker::spellingUIIsShowing())
6895 advanceToNextMisspelling(true);
6896 TextChecker::toggleSpellingUIIsShowing();
6897 return;
6898
6899 case ContextMenuItemTagAddHighlightToNewQuickNote:
6900#if ENABLE(APP_HIGHLIGHTS)
6901 createAppHighlightInSelectedRange(CreateNewGroupForHighlight::Yes, HighlightRequestOriginatedInApp::No);
6902#endif
6903 return;
6904
6905 case ContextMenuItemTagAddHighlightToCurrentQuickNote:
6906#if ENABLE(APP_HIGHLIGHTS)
6907 createAppHighlightInSelectedRange(CreateNewGroupForHighlight::No, HighlightRequestOriginatedInApp::No);
6908#endif
6909 return;
6910
6911 case ContextMenuItemTagLearnSpelling:
6912 case ContextMenuItemTagIgnoreSpelling:
6913 ++m_pendingLearnOrIgnoreWordMessageCount;
6914 break;
6915
6916 case ContextMenuItemTagQuickLookImage:
6917#if ENABLE(IMAGE_ANALYSIS)
6918 if (m_activeContextMenu)
6919 handleContextMenuQuickLookImage(m_activeContextMenu->quickLookPreviewActivity());
6920#endif
6921 return;
6922
6923 default:
6924 break;
6925 }
6926
6927 if (downloadInfo) {
6928 auto& download = m_process->processPool().download(m_websiteDataStore, this, URL(URL(), downloadInfo->url), downloadInfo->suggestedFilename);
6929 download.setDidStartCallback([this, weakThis = makeWeakPtr(*this)] (auto* download) {
6930 if (!weakThis || !download)
6931 return;
6932 m_navigationClient->contextMenuDidCreateDownload(*this, *download);
6933 });
6934 }
6935
6936 platformDidSelectItemFromActiveContextMenu(item);
6937
6938 send(Messages::WebPage::DidSelectItemFromActiveContextMenu(item));
6939}
6940
6941void WebPageProxy::handleContextMenuKeyEvent()
6942{
6943 send(Messages::WebPage::ContextMenuForKeyEvent());
6944}
6945#endif // ENABLE(CONTEXT_MENUS)
6946
6947#if PLATFORM(IOS_FAMILY)
6948void WebPageProxy::didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>& fileURLs, const String& displayString, const API::Data* iconData)
6949{
6950 if (!hasRunningProcess())
6951 return;
6952
6953#if ENABLE(SANDBOX_EXTENSIONS)
6954 auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("WebPageProxy::didChooseFilesForOpenPanelWithDisplayStringAndIcon"_s, fileURLs);
6955 send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)));
6956#endif
6957
6958 SandboxExtension::Handle frontboardServicesSandboxExtension, iconServicesSandboxExtension;
6959#if HAVE(FRONTBOARD_SYSTEM_APP_SERVICES)
6960 SandboxExtension::createHandleForMachLookup("com.apple.frontboard.systemappservices"_s, std::nullopt, frontboardServicesSandboxExtension);
6961#endif
6962 SandboxExtension::createHandleForMachLookup("com.apple.iconservices"_s, std::nullopt, iconServicesSandboxExtension);
6963
6964 send(Messages::WebPage::DidChooseFilesForOpenPanelWithDisplayStringAndIcon(fileURLs, displayString, iconData ? iconData->dataReference() : IPC::DataReference(), frontboardServicesSandboxExtension, iconServicesSandboxExtension));
6965
6966 m_openPanelResultListener->invalidate();
6967 m_openPanelResultListener = nullptr;
6968}
6969#endif
6970
6971bool WebPageProxy::didChooseFilesForOpenPanelWithImageTranscoding(const Vector<String>& fileURLs, const Vector<String>& allowedMIMETypes)
6972{
6973#if PLATFORM(MAC)
6974 auto transcodingMIMEType = WebCore::MIMETypeRegistry::preferredImageMIMETypeForEncoding(allowedMIMETypes, { });
6975 if (transcodingMIMEType.isNull())
6976 return false;
6977
6978 auto transcodingURLs = findImagesForTranscoding(fileURLs, allowedMIMETypes);
6979 if (transcodingURLs.isEmpty())
6980 return false;
6981
6982 auto transcodingUTI = WebCore::UTIFromMIMEType(transcodingMIMEType);
6983 auto transcodingExtension = WebCore::MIMETypeRegistry::preferredExtensionForMIMEType(transcodingMIMEType);
6984
6985 sharedImageTranscodingQueue().dispatch([this, protectedThis = makeRef(*this), fileURLs = fileURLs.isolatedCopy(), transcodingURLs = transcodingURLs.isolatedCopy(), transcodingUTI = transcodingUTI.isolatedCopy(), transcodingExtension = transcodingExtension.isolatedCopy()]() mutable {
6986 ASSERT(!RunLoop::isMain());
6987
6988 auto transcodedURLs = transcodeImages(transcodingURLs, transcodingUTI, transcodingExtension);
6989 ASSERT(transcodingURLs.size() == transcodedURLs.size());
6990
6991 RunLoop::main().dispatch([this, protectedThis = WTFMove(protectedThis), fileURLs = fileURLs.isolatedCopy(), transcodedURLs = transcodedURLs.isolatedCopy()]() {
6992#if ENABLE(SANDBOX_EXTENSIONS)
6993 Vector<String> sandboxExtensionFiles;
6994 for (size_t i = 0, size = fileURLs.size(); i < size; ++i)
6995 sandboxExtensionFiles.append(!transcodedURLs[i].isNull() ? transcodedURLs[i] : fileURLs[i]);
6996 auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("WebPageProxy::didChooseFilesForOpenPanel"_s, sandboxExtensionFiles);
6997 send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)));
6998#endif
6999 send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs, transcodedURLs));
7000 });
7001 });
7002
7003 return true;
7004#else
7005 UNUSED_PARAM(fileURLs);
7006 UNUSED_PARAM(allowedMIMETypes);
7007 return false;
7008#endif
7009}
7010
7011void WebPageProxy::didChooseFilesForOpenPanel(const Vector<String>& fileURLs, const Vector<String>& allowedMIMETypes)
7012{
7013 if (!hasRunningProcess())
7014 return;
7015
7016 if (!didChooseFilesForOpenPanelWithImageTranscoding(fileURLs, allowedMIMETypes)) {
7017#if ENABLE(SANDBOX_EXTENSIONS)
7018 auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("WebPageProxy::didChooseFilesForOpenPanel"_s, fileURLs);
7019 send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)));
7020#endif
7021 send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs, { }));
7022 }
7023
7024 m_openPanelResultListener->invalidate();
7025 m_openPanelResultListener = nullptr;
7026}
7027
7028void WebPageProxy::didCancelForOpenPanel()
7029{
7030 if (!hasRunningProcess())
7031 return;
7032
7033 send(Messages::WebPage::DidCancelForOpenPanel());
7034
7035 m_openPanelResultListener->invalidate();
7036 m_openPanelResultListener = nullptr;
7037}
7038
7039void WebPageProxy::advanceToNextMisspelling(bool startBeforeSelection)
7040{
7041 send(Messages::WebPage::AdvanceToNextMisspelling(startBeforeSelection));
7042}
7043
7044void WebPageProxy::changeSpellingToWord(const String& word)
7045{
7046 if (word.isEmpty())
7047 return;
7048
7049 send(Messages::WebPage::ChangeSpellingToWord(word));
7050}
7051
7052void WebPageProxy::registerEditCommand(Ref<WebEditCommandProxy>&& commandProxy, UndoOrRedo undoOrRedo)
7053{
7054 MESSAGE_CHECK(m_process, commandProxy->commandID());
7055 pageClient().registerEditCommand(WTFMove(commandProxy), undoOrRedo);
7056}
7057
7058void WebPageProxy::addEditCommand(WebEditCommandProxy& command)
7059{
7060 m_editCommandSet.add(&command);
7061}
7062
7063void WebPageProxy::removeEditCommand(WebEditCommandProxy& command)
7064{
7065 m_editCommandSet.remove(&command);
7066
7067 if (!hasRunningProcess())
7068 return;
7069 send(Messages::WebPage::DidRemoveEditCommand(command.commandID()));
7070}
7071
7072bool WebPageProxy::canUndo()
7073{
7074 return pageClient().canUndoRedo(UndoOrRedo::Undo);
7075}
7076
7077bool WebPageProxy::canRedo()
7078{
7079 return pageClient().canUndoRedo(UndoOrRedo::Redo);
7080}
7081
7082SpellDocumentTag WebPageProxy::spellDocumentTag()
7083{
7084 if (!m_spellDocumentTag)
7085 m_spellDocumentTag = TextChecker::uniqueSpellDocumentTag(this);
7086 return m_spellDocumentTag.value();
7087}
7088
7089#if USE(UNIFIED_TEXT_CHECKING)
7090void WebPageProxy::checkTextOfParagraph(const String& text, OptionSet<TextCheckingType> checkingTypes, int32_t insertionPoint, CompletionHandler<void(Vector<WebCore::TextCheckingResult>&&)>&& completionHandler)
7091{
7092 completionHandler(TextChecker::checkTextOfParagraph(spellDocumentTag(), text, insertionPoint, checkingTypes, m_initialCapitalizationEnabled));
7093}
7094#endif
7095
7096void WebPageProxy::checkSpellingOfString(const String& text, CompletionHandler<void(int32_t misspellingLocation, int32_t misspellingLength)>&& completionHandler)
7097{
7098 int32_t misspellingLocation = 0;
7099 int32_t misspellingLength = 0;
7100 TextChecker::checkSpellingOfString(spellDocumentTag(), text, misspellingLocation, misspellingLength);
7101 completionHandler(misspellingLocation, misspellingLength);
7102}
7103
7104void WebPageProxy::checkGrammarOfString(const String& text, CompletionHandler<void(Vector<WebCore::GrammarDetail>&&, int32_t badGrammarLocation, int32_t badGrammarLength)>&& completionHandler)
7105{
7106 Vector<GrammarDetail> grammarDetails;
7107 int32_t badGrammarLocation = 0;
7108 int32_t badGrammarLength = 0;
7109 TextChecker::checkGrammarOfString(spellDocumentTag(), text, grammarDetails, badGrammarLocation, badGrammarLength);
7110 completionHandler(WTFMove(grammarDetails), badGrammarLocation, badGrammarLength);
7111}
7112
7113void WebPageProxy::spellingUIIsShowing(CompletionHandler<void(bool)>&& completionHandler)
7114{
7115 completionHandler(TextChecker::spellingUIIsShowing());
7116}
7117
7118void WebPageProxy::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
7119{
7120 TextChecker::updateSpellingUIWithMisspelledWord(spellDocumentTag(), misspelledWord);
7121}
7122
7123void WebPageProxy::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
7124{
7125 TextChecker::updateSpellingUIWithGrammarString(spellDocumentTag(), badGrammarPhrase, grammarDetail);
7126}
7127
7128void WebPageProxy::getGuessesForWord(const String& word, const String& context, int32_t insertionPoint, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
7129{
7130 Vector<String> guesses;
7131 TextChecker::getGuessesForWord(spellDocumentTag(), word, context, insertionPoint, guesses, m_initialCapitalizationEnabled);
7132 completionHandler(WTFMove(guesses));
7133}
7134
7135void WebPageProxy::learnWord(const String& word)
7136{
7137 MESSAGE_CHECK(m_process, m_pendingLearnOrIgnoreWordMessageCount);
7138 --m_pendingLearnOrIgnoreWordMessageCount;
7139
7140 TextChecker::learnWord(spellDocumentTag(), word);
7141}
7142
7143void WebPageProxy::ignoreWord(const String& word)
7144{
7145 MESSAGE_CHECK(m_process, m_pendingLearnOrIgnoreWordMessageCount);
7146 --m_pendingLearnOrIgnoreWordMessageCount;
7147
7148 TextChecker::ignoreWord(spellDocumentTag(), word);
7149}
7150
7151void WebPageProxy::requestCheckingOfString(uint64_t requestID, const TextCheckingRequestData& request, int32_t insertionPoint)
7152{
7153 TextChecker::requestCheckingOfString(TextCheckerCompletion::create(requestID, request, this), insertionPoint);
7154}
7155
7156void WebPageProxy::didFinishCheckingText(uint64_t requestID, const Vector<WebCore::TextCheckingResult>& result)
7157{
7158 send(Messages::WebPage::DidFinishCheckingText(requestID, result));
7159}
7160
7161void WebPageProxy::didCancelCheckingText(uint64_t requestID)
7162{
7163 send(Messages::WebPage::DidCancelCheckingText(requestID));
7164}
7165// Other
7166
7167void WebPageProxy::setFocus(bool focused)
7168{
7169 if (focused)
7170 m_uiClient->focus(this);
7171 else
7172 m_uiClient->unfocus(this);
7173}
7174
7175void WebPageProxy::takeFocus(uint8_t direction)
7176{
7177 if (m_uiClient->takeFocus(this, (static_cast<FocusDirection>(direction) == FocusDirection::Forward) ? kWKFocusDirectionForward : kWKFocusDirectionBackward))
7178 return;
7179
7180 pageClient().takeFocus(static_cast<FocusDirection>(direction));
7181}
7182
7183void WebPageProxy::setToolTip(const String& toolTip)
7184{
7185 if (m_toolTip == toolTip)
7186 return;
7187
7188 String oldToolTip = m_toolTip;
7189 m_toolTip = toolTip;
7190 pageClient().toolTipChanged(oldToolTip, m_toolTip);
7191}
7192
7193void WebPageProxy::setCursor(const WebCore::Cursor& cursor)
7194{
7195 pageClient().setCursor(cursor);
7196}
7197
7198void WebPageProxy::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
7199{
7200 pageClient().setCursorHiddenUntilMouseMoves(hiddenUntilMouseMoves);
7201}
7202
7203void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled)
7204{
7205 WebEvent::Type type = static_cast<WebEvent::Type>(opaqueType);
7206
7207 switch (type) {
7208 case WebEvent::NoType:
7209 case WebEvent::MouseMove:
7210 case WebEvent::Wheel:
7211 break;
7212
7213 case WebEvent::MouseDown:
7214 case WebEvent::MouseUp:
7215 case WebEvent::MouseForceChanged:
7216 case WebEvent::MouseForceDown:
7217 case WebEvent::MouseForceUp:
7218 case WebEvent::KeyDown:
7219 case WebEvent::KeyUp:
7220 case WebEvent::RawKeyDown:
7221 case WebEvent::Char:
7222#if ENABLE(TOUCH_EVENTS)
7223 case WebEvent::TouchStart:
7224 case WebEvent::TouchMove:
7225 case WebEvent::TouchEnd:
7226 case WebEvent::TouchCancel:
7227#endif
7228#if ENABLE(MAC_GESTURE_EVENTS)
7229 case WebEvent::GestureStart:
7230 case WebEvent::GestureChange:
7231 case WebEvent::GestureEnd:
7232#endif
7233 m_process->stopResponsivenessTimer();
7234 break;
7235 }
7236
7237 switch (type) {
7238 case WebEvent::NoType:
7239 break;
7240 case WebEvent::MouseForceChanged:
7241 case WebEvent::MouseForceDown:
7242 case WebEvent::MouseForceUp:
7243 case WebEvent::MouseMove:
7244 case WebEvent::MouseDown:
7245 case WebEvent::MouseUp: {
7246 LOG(MouseHandling, "WebPageProxy::didReceiveEvent: %s (queue size %zu)", webMouseEventTypeString(type), m_mouseEventQueue.size());
7247
7248 // Retire the last sent event now that WebProcess is done handling it.
7249 MESSAGE_CHECK(m_process, !m_mouseEventQueue.isEmpty());
7250 auto event = m_mouseEventQueue.takeFirst();
7251 MESSAGE_CHECK(m_process, type == event.type());
7252
7253 if (!m_mouseEventQueue.isEmpty()) {
7254 LOG(MouseHandling, " UIProcess: handling a queued mouse event from didReceiveEvent");
7255 processNextQueuedMouseEvent();
7256 } else {
7257 if (auto* automationSession = process().processPool().automationSession())
7258 automationSession->mouseEventsFlushedForPage(*this);
7259 didFinishProcessingAllPendingMouseEvents();
7260 }
7261 break;
7262 }
7263
7264 case WebEvent::Wheel: {
7265 MESSAGE_CHECK(m_process, wheelEventCoalescer().hasEventsBeingProcessed());
7266 auto oldestProcessedEvent = wheelEventCoalescer().takeOldestEventBeingProcessed();
7267
7268 // FIXME: Dispatch additional events to the didNotHandleWheelEvent client function.
7269 if (!handled) {
7270 m_uiClient->didNotHandleWheelEvent(this, oldestProcessedEvent);
7271 pageClient().wheelEventWasNotHandledByWebCore(oldestProcessedEvent);
7272 }
7273
7274 if (auto eventToSend = wheelEventCoalescer().nextEventToDispatch())
7275 sendWheelEvent(*eventToSend);
7276 else if (auto* automationSession = process().processPool().automationSession())
7277 automationSession->wheelEventsFlushedForPage(*this);
7278 break;
7279 }
7280
7281 case WebEvent::KeyDown:
7282 case WebEvent::KeyUp:
7283 case WebEvent::RawKeyDown:
7284 case WebEvent::Char: {
7285 LOG(KeyHandling, "WebPageProxy::didReceiveEvent: %s (queue empty %d)", webKeyboardEventTypeString(type), m_keyEventQueue.isEmpty());
7286
7287 MESSAGE_CHECK(m_process, !m_keyEventQueue.isEmpty());
7288 auto event = m_keyEventQueue.takeFirst();
7289 MESSAGE_CHECK(m_process, type == event.type());
7290
7291#if PLATFORM(WIN)
7292 if (!handled && type == WebEvent::RawKeyDown)
7293 dispatchPendingCharEvents(event);
7294#endif
7295
7296 bool canProcessMoreKeyEvents = !m_keyEventQueue.isEmpty();
7297 if (canProcessMoreKeyEvents) {
7298 LOG(KeyHandling, " UI process: sent keyEvent from didReceiveEvent");
7299 send(Messages::WebPage::KeyEvent(m_keyEventQueue.first()));
7300 }
7301
7302 // The call to doneWithKeyEvent may close this WebPage.
7303 // Protect against this being destroyed.
7304 Ref<WebPageProxy> protect(*this);
7305
7306 pageClient().doneWithKeyEvent(event, handled);
7307 if (!handled)
7308 m_uiClient->didNotHandleKeyEvent(this, event);
7309
7310 // Notify the session after -[NSApp sendEvent:] has a crack at turning the event into an action.
7311 if (!canProcessMoreKeyEvents) {
7312 if (auto* automationSession = process().processPool().automationSession())
7313 automationSession->keyboardEventsFlushedForPage(*this);
7314 }
7315 break;
7316 }
7317#if ENABLE(MAC_GESTURE_EVENTS)
7318 case WebEvent::GestureStart:
7319 case WebEvent::GestureChange:
7320 case WebEvent::GestureEnd: {
7321 MESSAGE_CHECK(m_process, !m_gestureEventQueue.isEmpty());
7322 auto event = m_gestureEventQueue.takeFirst();
7323 MESSAGE_CHECK(m_process, type == event.type());
7324
7325 if (!handled)
7326 pageClient().gestureEventWasNotHandledByWebCore(event);
7327 break;
7328 }
7329#endif
7330#if ENABLE(IOS_TOUCH_EVENTS)
7331 case WebEvent::TouchStart:
7332 case WebEvent::TouchMove:
7333 case WebEvent::TouchEnd:
7334 case WebEvent::TouchCancel:
7335 break;
7336#elif ENABLE(TOUCH_EVENTS)
7337 case WebEvent::TouchStart:
7338 case WebEvent::TouchMove:
7339 case WebEvent::TouchEnd:
7340 case WebEvent::TouchCancel: {
7341 MESSAGE_CHECK(m_process, !m_touchEventQueue.isEmpty());
7342 auto queuedEvents = m_touchEventQueue.takeFirst();
7343 MESSAGE_CHECK(m_process, type == queuedEvents.forwardedEvent.type());
7344
7345 pageClient().doneWithTouchEvent(queuedEvents.forwardedEvent, handled);
7346 for (size_t i = 0; i < queuedEvents.deferredTouchEvents.size(); ++i) {
7347 bool isEventHandled = false;
7348 pageClient().doneWithTouchEvent(queuedEvents.deferredTouchEvents.at(i), isEventHandled);
7349 }
7350 break;
7351 }
7352#endif
7353 }
7354}
7355
7356void WebPageProxy::editorStateChanged(const EditorState& editorState)
7357{
7358 if (updateEditorState(editorState))
7359 dispatchDidUpdateEditorState();
7360}
7361
7362bool WebPageProxy::updateEditorState(const EditorState& newEditorState)
7363{
7364 if (newEditorState.transactionID < m_editorState.transactionID)
7365 return false;
7366
7367 auto oldEditorState = std::exchange(m_editorState, newEditorState);
7368 didUpdateEditorState(oldEditorState, newEditorState);
7369 return true;
7370}
7371
7372#if !PLATFORM(IOS_FAMILY)
7373
7374void WebPageProxy::dispatchDidUpdateEditorState()
7375{
7376}
7377
7378#endif
7379
7380inline API::DiagnosticLoggingClient* WebPageProxy::effectiveDiagnosticLoggingClient(ShouldSample shouldSample)
7381{
7382 // Diagnostic logging is disabled for ephemeral sessions for privacy reasons.
7383 if (sessionID().isEphemeral())
7384 return nullptr;
7385
7386 return DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample) ? diagnosticLoggingClient() : nullptr;
7387}
7388
7389void WebPageProxy::logDiagnosticMessage(const String& message, const String& description, WebCore::ShouldSample shouldSample)
7390{
7391 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7392 if (!effectiveClient)
7393 return;
7394
7395 effectiveClient->logDiagnosticMessage(this, message, description);
7396}
7397
7398void WebPageProxy::logDiagnosticMessageFromWebProcess(const String& message, const String& description, WebCore::ShouldSample shouldSample)
7399{
7400 MESSAGE_CHECK(m_process, message.isAllASCII());
7401
7402 logDiagnosticMessage(message, description, shouldSample);
7403}
7404
7405void WebPageProxy::logDiagnosticMessageWithResult(const String& message, const String& description, uint32_t result, WebCore::ShouldSample shouldSample)
7406{
7407 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7408 if (!effectiveClient)
7409 return;
7410
7411 effectiveClient->logDiagnosticMessageWithResult(this, message, description, static_cast<WebCore::DiagnosticLoggingResultType>(result));
7412}
7413
7414void WebPageProxy::logDiagnosticMessageWithResultFromWebProcess(const String& message, const String& description, uint32_t result, WebCore::ShouldSample shouldSample)
7415{
7416 MESSAGE_CHECK(m_process, message.isAllASCII());
7417
7418 logDiagnosticMessageWithResult(message, description, result, shouldSample);
7419}
7420
7421void WebPageProxy::logDiagnosticMessageWithValue(const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample)
7422{
7423 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7424 if (!effectiveClient)
7425 return;
7426
7427 effectiveClient->logDiagnosticMessageWithValue(this, message, description, String::numberToStringFixedPrecision(value, significantFigures));
7428}
7429
7430void WebPageProxy::logDiagnosticMessageWithValueFromWebProcess(const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample)
7431{
7432 MESSAGE_CHECK(m_process, message.isAllASCII());
7433
7434 logDiagnosticMessageWithValue(message, description, value, significantFigures, shouldSample);
7435}
7436
7437void WebPageProxy::logDiagnosticMessageWithEnhancedPrivacy(const String& message, const String& description, ShouldSample shouldSample)
7438{
7439 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7440 if (!effectiveClient)
7441 return;
7442
7443 effectiveClient->logDiagnosticMessageWithEnhancedPrivacy(this, message, description);
7444}
7445
7446void WebPageProxy::logDiagnosticMessageWithEnhancedPrivacyFromWebProcess(const String& message, const String& description, WebCore::ShouldSample shouldSample)
7447{
7448 MESSAGE_CHECK(m_process, message.isAllASCII());
7449
7450 logDiagnosticMessageWithEnhancedPrivacy(message, description, shouldSample);
7451}
7452
7453void WebPageProxy::logDiagnosticMessageWithValueDictionary(const String& message, const String& description, const WebCore::DiagnosticLoggingClient::ValueDictionary& valueDictionary, WebCore::ShouldSample shouldSample)
7454{
7455 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7456 if (!effectiveClient)
7457 return;
7458
7459 auto apiDictionary = API::Dictionary::create();
7460
7461 for (auto& keyValuePair : valueDictionary) {
7462 apiDictionary->add(keyValuePair.key, WTF::switchOn(keyValuePair.value,
7463 [](const String& value) -> Ref<Object> { return API::String::create(value); },
7464 [](uint64_t value) -> Ref<Object> { return API::UInt64::create(value); },
7465 [](int64_t value) -> Ref<Object> { return API::Int64::create(value); },
7466 [](bool value) -> Ref<Object> { return API::Boolean::create(value); },
7467 [](double value) -> Ref<Object> { return API::Double::create(value); }
7468 ));
7469 }
7470
7471 effectiveClient->logDiagnosticMessageWithValueDictionary(this, message, description, WTFMove(apiDictionary));
7472}
7473
7474void WebPageProxy::logDiagnosticMessageWithValueDictionaryFromWebProcess(const String& message, const String& description, const WebCore::DiagnosticLoggingClient::ValueDictionary& valueDictionary, WebCore::ShouldSample shouldSample)
7475{
7476 MESSAGE_CHECK(m_process, message.isAllASCII());
7477
7478 logDiagnosticMessageWithValueDictionary(message, description, valueDictionary, shouldSample);
7479}
7480
7481void WebPageProxy::logDiagnosticMessageWithDomain(const String& message, WebCore::DiagnosticLoggingDomain domain)
7482{
7483 auto* effectiveClient = effectiveDiagnosticLoggingClient(ShouldSample::No);
7484 if (!effectiveClient)
7485 return;
7486
7487 effectiveClient->logDiagnosticMessageWithDomain(this, message, domain);
7488}
7489
7490void WebPageProxy::logDiagnosticMessageWithDomainFromWebProcess(const String& message, WebCore::DiagnosticLoggingDomain domain)
7491{
7492 MESSAGE_CHECK(m_process, message.isAllASCII());
7493
7494 logDiagnosticMessageWithDomain(message, domain);
7495}
7496
7497void WebPageProxy::logScrollingEvent(uint32_t eventType, MonotonicTime timestamp, uint64_t data)
7498{
7499 PerformanceLoggingClient::ScrollingEvent event = static_cast<PerformanceLoggingClient::ScrollingEvent>(eventType);
7500
7501 switch (event) {
7502 case PerformanceLoggingClient::ScrollingEvent::LoggingEnabled:
7503 WTFLogAlways("SCROLLING: ScrollingPerformanceTestingEnabled\n");
7504 break;
7505 case PerformanceLoggingClient::ScrollingEvent::ExposedTilelessArea:
7506 WTFLogAlways("SCROLLING: Exposed tileless area. Time: %f Unfilled Pixels: %llu\n", timestamp.secondsSinceEpoch().value(), (unsigned long long)data);
7507 break;
7508 case PerformanceLoggingClient::ScrollingEvent::FilledTile:
7509 WTFLogAlways("SCROLLING: Filled visible fresh tile. Time: %f Unfilled Pixels: %llu\n", timestamp.secondsSinceEpoch().value(), (unsigned long long)data);
7510 break;
7511 case PerformanceLoggingClient::ScrollingEvent::SwitchedScrollingMode:
7512 if (data)
7513 WTFLogAlways("SCROLLING: Switching to main-thread scrolling mode. Time: %f Reason(s): %s\n", timestamp.secondsSinceEpoch().value(), PerformanceLoggingClient::synchronousScrollingReasonsAsString(OptionSet<SynchronousScrollingReason>::fromRaw(data)).utf8().data());
7514 else
7515 WTFLogAlways("SCROLLING: Switching to threaded scrolling mode. Time: %f\n", timestamp.secondsSinceEpoch().value());
7516 break;
7517 }
7518}
7519
7520void WebPageProxy::focusedFrameChanged(const std::optional<FrameIdentifier>& frameID)
7521{
7522 if (!frameID) {
7523 m_focusedFrame = nullptr;
7524 return;
7525 }
7526
7527 WebFrameProxy* frame = m_process->webFrame(*frameID);
7528 MESSAGE_CHECK(m_process, frame);
7529
7530 m_focusedFrame = frame;
7531}
7532
7533void WebPageProxy::processDidBecomeUnresponsive()
7534{
7535 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "processDidBecomeUnresponsive:");
7536
7537 if (!hasRunningProcess())
7538 return;
7539
7540 updateBackingStoreDiscardableState();
7541
7542 m_navigationClient->processDidBecomeUnresponsive(*this);
7543}
7544
7545void WebPageProxy::processDidBecomeResponsive()
7546{
7547 WEBPAGEPROXY_RELEASE_LOG(Process, "processDidBecomeResponsive:");
7548
7549 if (!hasRunningProcess())
7550 return;
7551
7552 updateBackingStoreDiscardableState();
7553
7554 m_navigationClient->processDidBecomeResponsive(*this);
7555}
7556
7557void WebPageProxy::willChangeProcessIsResponsive()
7558{
7559 m_pageLoadState.willChangeProcessIsResponsive();
7560}
7561
7562void WebPageProxy::didChangeProcessIsResponsive()
7563{
7564 m_pageLoadState.didChangeProcessIsResponsive();
7565}
7566
7567String WebPageProxy::currentURL() const
7568{
7569 String url = m_pageLoadState.activeURL();
7570 if (url.isEmpty() && m_backForwardList->currentItem())
7571 url = m_backForwardList->currentItem()->url();
7572 return url;
7573}
7574
7575URL WebPageProxy::currentResourceDirectoryURL() const
7576{
7577 auto resourceDirectoryURL = m_pageLoadState.resourceDirectoryURL();
7578 if (!resourceDirectoryURL.isEmpty())
7579 return resourceDirectoryURL;
7580 if (auto* item = m_backForwardList->currentItem())
7581 return item->resourceDirectoryURL();
7582 return { };
7583}
7584
7585void WebPageProxy::resetStateAfterProcessTermination(ProcessTerminationReason reason)
7586{
7587 if (reason != ProcessTerminationReason::NavigationSwap)
7588 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "processDidTerminate: (pid %d), reason %d", processIdentifier(), reason);
7589
7590 ASSERT(m_hasRunningProcess);
7591
7592#if PLATFORM(IOS_FAMILY)
7593 if (m_process->isUnderMemoryPressure()) {
7594 String domain = WebCore::topPrivatelyControlledDomain(URL({ }, currentURL()).host().toString());
7595 if (!domain.isEmpty())
7596 logDiagnosticMessageWithEnhancedPrivacy(WebCore::DiagnosticLoggingKeys::domainCausingJetsamKey(), domain, WebCore::ShouldSample::No);
7597 }
7598#endif
7599
7600 resetStateAfterProcessExited(reason);
7601 stopAllURLSchemeTasks(m_process.ptr());
7602#if ENABLE(UI_PROCESS_PDF_HUD)
7603 pageClient().removeAllPDFHUDs();
7604#endif
7605
7606 // For bringup of process swapping, NavigationSwap termination will not go out to clients.
7607 // If it does *during* process swapping, and the client triggers a reload, that causes bizarre WebKit re-entry.
7608 // FIXME: This might have to change
7609 if (reason != ProcessTerminationReason::NavigationSwap)
7610 navigationState().clearAllNavigations();
7611
7612 if (m_controlledByAutomation) {
7613 if (auto* automationSession = process().processPool().automationSession())
7614 automationSession->terminate();
7615 }
7616}
7617
7618void WebPageProxy::provisionalProcessDidTerminate()
7619{
7620 ASSERT(m_provisionalPage);
7621 m_provisionalPage = nullptr;
7622}
7623
7624static bool shouldReloadAfterProcessTermination(ProcessTerminationReason reason)
7625{
7626 switch (reason) {
7627 case ProcessTerminationReason::ExceededMemoryLimit:
7628 case ProcessTerminationReason::ExceededCPULimit:
7629 case ProcessTerminationReason::RequestedByNetworkProcess:
7630 case ProcessTerminationReason::RequestedByGPUProcess:
7631 case ProcessTerminationReason::Crash:
7632 return true;
7633 case ProcessTerminationReason::NavigationSwap:
7634 case ProcessTerminationReason::RequestedByClient:
7635 break;
7636 }
7637 return false;
7638}
7639
7640void WebPageProxy::dispatchProcessDidTerminate(ProcessTerminationReason reason)
7641{
7642 WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "dispatchProcessDidTerminate: reason=%d", reason);
7643
7644 bool handledByClient = false;
7645 if (m_loaderClient)
7646 handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this);
7647 else
7648 handledByClient = m_navigationClient->processDidTerminate(*this, reason);
7649
7650 if (!handledByClient && shouldReloadAfterProcessTermination(reason))
7651 tryReloadAfterProcessTermination();
7652}
7653
7654void WebPageProxy::tryReloadAfterProcessTermination()
7655{
7656 m_resetRecentCrashCountTimer.stop();
7657
7658 if (++m_recentCrashCount > maximumWebProcessRelaunchAttempts) {
7659 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "tryReloadAfterProcessTermination: process crashed and the client did not handle it, not reloading the page because we reached the maximum number of attempts");
7660 m_recentCrashCount = 0;
7661 return;
7662 }
7663 WEBPAGEPROXY_RELEASE_LOG(Process, "tryReloadAfterProcessTermination: process crashed and the client did not handle it, reloading the page");
7664 reload(ReloadOption::ExpiredOnly);
7665}
7666
7667void WebPageProxy::resetRecentCrashCountSoon()
7668{
7669 m_resetRecentCrashCountTimer.startOneShot(resetRecentCrashCountDelay);
7670}
7671
7672void WebPageProxy::resetRecentCrashCount()
7673{
7674 m_recentCrashCount = 0;
7675}
7676
7677void WebPageProxy::stopAllURLSchemeTasks(WebProcessProxy* process)
7678{
7679 for (auto& handler : copyToVectorOf<Ref<WebURLSchemeHandler>>(m_urlSchemeHandlersByScheme.values()))
7680 handler->stopAllTasksForPage(*this, process);
7681}
7682
7683void WebPageProxy::resetState(ResetStateReason resetStateReason)
7684{
7685 m_mainFrame = nullptr;
7686 m_focusedFrame = nullptr;
7687 m_suspendedPageKeptToPreventFlashing = nullptr;
7688 m_lastSuspendedPage = nullptr;
7689
7690#if PLATFORM(COCOA)
7691 m_scrollingPerformanceData = nullptr;
7692#endif
7693
7694 if (m_drawingArea) {
7695#if PLATFORM(COCOA)
7696 if (resetStateReason == ResetStateReason::NavigationSwap && is<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea)) {
7697 // Keep layers around in frozen state to avoid flashing during process swaps.
7698 m_frozenRemoteLayerTreeHost = downcast<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea).detachRemoteLayerTreeHost();
7699 }
7700#endif
7701 m_drawingArea = nullptr;
7702 }
7703 closeOverlayedViews();
7704
7705 m_inspector->reset();
7706
7707#if ENABLE(FULLSCREEN_API)
7708 if (m_fullScreenManager) {
7709 m_fullScreenManager->close();
7710 m_fullScreenManager = nullptr;
7711 }
7712#endif
7713
7714#if ENABLE(MEDIA_USAGE)
7715 if (m_mediaUsageManager)
7716 m_mediaUsageManager->reset();
7717#endif
7718
7719#if HAVE(VISIBILITY_PROPAGATION_VIEW)
7720 if (resetStateReason != ResetStateReason::NavigationSwap)
7721 m_contextIDForVisibilityPropagationInWebProcess = 0;
7722#endif
7723
7724 if (m_openPanelResultListener) {
7725 m_openPanelResultListener->invalidate();
7726 m_openPanelResultListener = nullptr;
7727 }
7728
7729#if ENABLE(TOUCH_EVENTS)
7730 m_touchAndPointerEventTracking.reset();
7731#endif
7732
7733#if ENABLE(GEOLOCATION)
7734 m_geolocationPermissionRequestManager.invalidateRequests();
7735#endif
7736
7737 setToolTip({ });
7738
7739 m_mainFrameHasHorizontalScrollbar = false;
7740 m_mainFrameHasVerticalScrollbar = false;
7741
7742 m_mainFrameIsPinnedToLeftSide = true;
7743 m_mainFrameIsPinnedToRightSide = true;
7744 m_mainFrameIsPinnedToTopSide = true;
7745 m_mainFrameIsPinnedToBottomSide = true;
7746
7747 m_visibleScrollerThumbRect = IntRect();
7748
7749#if ENABLE(VIDEO_PRESENTATION_MODE)
7750 if (m_playbackSessionManager) {
7751 m_playbackSessionManager->invalidate();
7752 m_playbackSessionManager = nullptr;
7753 }
7754 if (m_videoFullscreenManager) {
7755 m_videoFullscreenManager->invalidate();
7756 m_videoFullscreenManager = nullptr;
7757 }
7758#endif
7759
7760#if PLATFORM(IOS_FAMILY)
7761 m_firstLayerTreeTransactionIdAfterDidCommitLoad = { };
7762 m_lastVisibleContentRectUpdate = { };
7763 m_hasNetworkRequestsOnSuspended = false;
7764 m_isKeyboardAnimatingIn = false;
7765 m_isScrollingOrZooming = false;
7766 m_lastObservedStateWasBackground = false;
7767#endif
7768
7769#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
7770 pageClient().mediaSessionManager().removeAllPlaybackTargetPickerClients(*this);
7771#endif
7772
7773#if ENABLE(APPLE_PAY)
7774 m_paymentCoordinator = nullptr;
7775#endif
7776
7777#if USE(SYSTEM_PREVIEW)
7778 m_systemPreviewController = nullptr;
7779#endif
7780
7781#if HAVE(ARKIT_INLINE_PREVIEW)
7782 m_modelElementController = nullptr;
7783#endif
7784
7785#if ENABLE(WEB_AUTHN)
7786 m_credentialsMessenger = nullptr;
7787#endif
7788
7789#if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
7790 m_webDeviceOrientationUpdateProviderProxy = nullptr;
7791#endif
7792
7793 for (auto& editCommand : std::exchange(m_editCommandSet, { }))
7794 editCommand->invalidate();
7795
7796 m_activePopupMenu = nullptr;
7797
7798 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
7799#if ENABLE(MEDIA_STREAM)
7800 m_userMediaPermissionRequestManager = nullptr;
7801#endif
7802
7803#if ENABLE(POINTER_LOCK)
7804 requestPointerUnlock();
7805#endif
7806
7807#if ENABLE(SPEECH_SYNTHESIS)
7808 resetSpeechSynthesizer();
7809#endif
7810
7811#if ENABLE(WEB_AUTHN)
7812 m_websiteDataStore->authenticatorManager().cancelRequest(m_webPageID, std::nullopt);
7813#endif
7814
7815 m_speechRecognitionPermissionManager = nullptr;
7816
7817#if ENABLE(WEBXR) && PLATFORM(COCOA)
7818 if (m_xrSystem) {
7819 m_xrSystem->invalidate();
7820 m_xrSystem = nullptr;
7821 }
7822#endif
7823}
7824
7825void WebPageProxy::resetStateAfterProcessExited(ProcessTerminationReason terminationReason)
7826{
7827 if (!hasRunningProcess())
7828 return;
7829
7830 PageClientProtector protector(pageClient());
7831
7832#if ASSERT_ENABLED
7833 // FIXME: It's weird that resetStateAfterProcessExited() is called even though the process is launching.
7834 if (terminationReason != ProcessTerminationReason::NavigationSwap)
7835 ASSERT(m_process->state() == WebProcessProxy::State::Launching || m_process->state() == WebProcessProxy::State::Terminated);
7836#endif
7837
7838#if PLATFORM(IOS_FAMILY)
7839 m_waitingForPostLayoutEditorStateUpdateAfterFocusingElement = false;
7840 m_isVisibleActivity = nullptr;
7841 m_isAudibleActivity = nullptr;
7842 m_isCapturingActivity = nullptr;
7843 m_openingAppLinkActivity = nullptr;
7844#endif
7845
7846 m_pageIsUserObservableCount = nullptr;
7847 m_visiblePageToken = nullptr;
7848
7849 m_hasRunningProcess = false;
7850 m_areActiveDOMObjectsAndAnimationsSuspended = false;
7851
7852 m_userScriptsNotified = false;
7853
7854 m_editorState = EditorState();
7855 m_cachedFontAttributesAtSelectionStart.reset();
7856
7857 if (terminationReason == ProcessTerminationReason::NavigationSwap)
7858 pageClient().processWillSwap();
7859 else
7860 pageClient().processDidExit();
7861
7862 pageClient().clearAllEditCommands();
7863
7864#if PLATFORM(COCOA)
7865 WebPasteboardProxy::singleton().revokeAccess(m_process.get());
7866#endif
7867
7868 auto resetStateReason = terminationReason == ProcessTerminationReason::NavigationSwap ? ResetStateReason::NavigationSwap : ResetStateReason::WebProcessExited;
7869 resetState(resetStateReason);
7870
7871 m_pendingLearnOrIgnoreWordMessageCount = 0;
7872
7873 // Can't expect DidReceiveEvent notifications from a crashed web process.
7874 m_mouseEventQueue.clear();
7875 m_keyEventQueue.clear();
7876 if (m_wheelEventCoalescer)
7877 m_wheelEventCoalescer->clear();
7878
7879#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
7880 m_touchEventQueue.clear();
7881#endif
7882
7883#if ENABLE(ATTACHMENT_ELEMENT)
7884 invalidateAllAttachments();
7885#endif
7886
7887#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
7888 if (m_scrollingCoordinatorProxy)
7889 m_scrollingCoordinatorProxy->resetStateAfterProcessExited();
7890#endif
7891
7892 if (terminationReason != ProcessTerminationReason::NavigationSwap) {
7893 PageLoadState::Transaction transaction = m_pageLoadState.transaction();
7894 m_pageLoadState.reset(transaction);
7895 }
7896
7897 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
7898
7899 // FIXME: <rdar://problem/38676604> In case of process swaps, the old process should gracefully suspend instead of terminating.
7900 m_process->processTerminated();
7901}
7902
7903#if ENABLE(ATTACHMENT_ELEMENT) && PLATFORM(COCOA)
7904static const Vector<ASCIILiteral>& attachmentElementServices()
7905{
7906 static const auto services = makeNeverDestroyed(Vector<ASCIILiteral> {
7907#if PLATFORM(IOS_FAMILY)
7908 "com.apple.frontboard.systemappservices"_s,
7909#endif
7910 "com.apple.iconservices"_s,
7911#if PLATFORM(MAC)
7912 "com.apple.iconservices.store"_s,
7913#endif
7914 });
7915 return services;
7916}
7917#endif
7918
7919#if PLATFORM(COCOA)
7920static const Vector<ASCIILiteral>& gpuIOKitClasses()
7921{
7922 ASSERT(isMainRunLoop());
7923 static const auto services = makeNeverDestroyed(Vector<ASCIILiteral> {
7924#if PLATFORM(IOS_FAMILY)
7925 "AGXDeviceUserClient"_s,
7926 "IOGPU"_s,
7927 "IOSurfaceRootUserClient"_s,
7928#endif
7929#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
7930 "AGPMClient"_s,
7931 "AppleGraphicsControlClient"_s,
7932 "AppleGraphicsPolicyClient"_s,
7933 "AppleIntelMEUserClient"_s,
7934 "AppleMGPUPowerControlClient"_s,
7935 "AppleSNBFBUserClient"_s,
7936 "AppleUpstreamUserClient"_s,
7937 "AudioAUUC"_s,
7938 "IOAccelerationUserClient"_s,
7939 "IOAccelerator"_s,
7940 "IOAudioControlUserClient"_s,
7941 "IOAudioEngineUserClient"_s,
7942 "IOSurfaceRootUserClient"_s,
7943#endif
7944#if (PLATFORM(MAC) && CPU(ARM64)) || PLATFORM(IOS_FAMILY)
7945 "IOMobileFramebufferUserClient"_s,
7946 "IOSurfaceAcceleratorClient"_s,
7947#endif
7948 });
7949 return services;
7950}
7951
7952static const Vector<ASCIILiteral>& gpuMachServices()
7953{
7954 ASSERT(isMainRunLoop());
7955 static const auto services = makeNeverDestroyed(Vector<ASCIILiteral> {
7956 "com.apple.MTLCompilerService"_s,
7957#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
7958 "com.apple.cvmsServ"_s,
7959#endif
7960 });
7961 return services;
7962}
7963
7964// FIXME(207716): The following should be removed when the GPU process is complete.
7965static const Vector<ASCIILiteral>& mediaRelatedMachServices()
7966{
7967 ASSERT(isMainRunLoop());
7968 static const auto services = makeNeverDestroyed(Vector<ASCIILiteral> {
7969 "com.apple.audio.AudioComponentPrefs"_s, "com.apple.audio.AudioComponentRegistrar"_s,
7970 "com.apple.audio.AudioQueueServer"_s, "com.apple.coremedia.endpoint.xpc"_s,
7971 "com.apple.coremedia.routediscoverer.xpc"_s, "com.apple.coremedia.routingcontext.xpc"_s,
7972 "com.apple.coremedia.volumecontroller.xpc"_s, "com.apple.accessibility.mediaaccessibilityd"_s,
7973 "com.apple.mediaremoted.xpc"_s,
7974#if PLATFORM(IOS_FAMILY)
7975 "com.apple.audio.AudioSession"_s, "com.apple.MediaPlayer.RemotePlayerService"_s,
7976 "com.apple.coremedia.admin"_s,
7977 "com.apple.coremedia.asset.xpc"_s, "com.apple.coremedia.assetimagegenerator.xpc"_s,
7978 "com.apple.coremedia.audiodeviceclock.xpc"_s, "com.apple.coremedia.audioprocessingtap.xpc"_s,
7979 "com.apple.coremedia.capturesession"_s, "com.apple.coremedia.capturesource"_s,
7980 "com.apple.coremedia.compressionsession"_s, "com.apple.coremedia.cpe.xpc"_s,
7981 "com.apple.coremedia.cpeprotector.xpc"_s, "com.apple.coremedia.customurlloader.xpc"_s,
7982 "com.apple.coremedia.decompressionsession"_s, "com.apple.coremedia.figcontentkeysession.xpc"_s,
7983 "com.apple.coremedia.figcpecryptor"_s, "com.apple.coremedia.formatreader.xpc"_s,
7984 "com.apple.coremedia.player.xpc"_s, "com.apple.coremedia.remaker"_s,
7985 "com.apple.coremedia.remotequeue"_s, "com.apple.coremedia.routingsessionmanager.xpc"_s,
7986 "com.apple.coremedia.samplebufferaudiorenderer.xpc"_s, "com.apple.coremedia.samplebufferrendersynchronizer.xpc"_s,
7987 "com.apple.coremedia.sandboxserver.xpc"_s, "com.apple.coremedia.sts"_s,
7988 "com.apple.coremedia.systemcontroller.xpc"_s, "com.apple.coremedia.videoqueue"_s,
7989 "com.apple.coremedia.visualcontext.xpc"_s, "com.apple.airplay.apsynccontroller.xpc"_s,
7990 "com.apple.audio.AURemoteIOServer"_s,
7991#endif
7992#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
7993 "com.apple.audio.audiohald"_s, "com.apple.audio.SandboxHelper"_s, "com.apple.coremedia.endpointstream.xpc"_s, "com.apple.coremedia.endpointplaybacksession.xpc"_s,
7994 "com.apple.coremedia.endpointremotecontrolsession.xpc"_s, "com.apple.coremedia.videodecoder"_s,
7995 "com.apple.coremedia.videoencoder"_s, "com.apple.lskdd"_s, "com.apple.trustd.agent"_s,
7996#endif
7997 });
7998 return services;
7999}
8000
8001static const Vector<ASCIILiteral>& mediaRelatedIOKitClasses()
8002{
8003 static const auto services = makeNeverDestroyed(Vector<ASCIILiteral> {
8004#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
8005#if CPU(ARM64)
8006 "AppleAVDUserClient"_s,
8007#endif
8008 "RootDomainUserClient"_s,
8009#endif
8010 });
8011 return services;
8012}
8013#endif
8014
8015WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& process, DrawingAreaProxy& drawingArea, RefPtr<API::WebsitePolicies>&& websitePolicies)
8016{
8017 WebPageCreationParameters parameters;
8018
8019 parameters.processDisplayName = configuration().processDisplayName();
8020
8021 parameters.viewSize = pageClient().viewSize();
8022 parameters.activityState = m_activityState;
8023 parameters.drawingAreaType = drawingArea.type();
8024 parameters.drawingAreaIdentifier = drawingArea.identifier();
8025 parameters.webPageProxyIdentifier = m_identifier;
8026 parameters.store = preferencesStore();
8027 parameters.pageGroupData = m_pageGroup->data();
8028 parameters.isEditable = m_isEditable;
8029 parameters.underlayColor = m_underlayColor;
8030 parameters.useFixedLayout = m_useFixedLayout;
8031 parameters.fixedLayoutSize = m_fixedLayoutSize;
8032 parameters.viewExposedRect = m_viewExposedRect;
8033 parameters.alwaysShowsHorizontalScroller = m_alwaysShowsHorizontalScroller;
8034 parameters.alwaysShowsVerticalScroller = m_alwaysShowsVerticalScroller;
8035 parameters.suppressScrollbarAnimations = m_suppressScrollbarAnimations;
8036 parameters.paginationMode = m_paginationMode;
8037 parameters.paginationBehavesLikeColumns = m_paginationBehavesLikeColumns;
8038 parameters.pageLength = m_pageLength;
8039 parameters.gapBetweenPages = m_gapBetweenPages;
8040 parameters.paginationLineGridEnabled = m_paginationLineGridEnabled;
8041 parameters.userAgent = userAgent();
8042 parameters.itemStatesWereRestoredByAPIRequest = m_sessionStateWasRestoredByAPIRequest;
8043 parameters.itemStates = m_backForwardList->itemStates();
8044 parameters.visitedLinkTableID = m_visitedLinkStore->identifier();
8045 parameters.canRunBeforeUnloadConfirmPanel = m_uiClient->canRunBeforeUnloadConfirmPanel();
8046 parameters.canRunModal = m_canRunModal;
8047 parameters.deviceScaleFactor = deviceScaleFactor();
8048 parameters.viewScaleFactor = m_viewScaleFactor;
8049 parameters.textZoomFactor = m_textZoomFactor;
8050 parameters.pageZoomFactor = m_pageZoomFactor;
8051 parameters.topContentInset = m_topContentInset;
8052 parameters.mediaVolume = m_mediaVolume;
8053 parameters.muted = m_mutedState;
8054 parameters.mayStartMediaWhenInWindow = m_mayStartMediaWhenInWindow;
8055 parameters.mediaPlaybackIsSuspended = m_mediaPlaybackIsSuspended;
8056 parameters.minimumSizeForAutoLayout = m_minimumSizeForAutoLayout;
8057 parameters.sizeToContentAutoSizeMaximumSize = m_sizeToContentAutoSizeMaximumSize;
8058 parameters.autoSizingShouldExpandToViewHeight = m_autoSizingShouldExpandToViewHeight;
8059 parameters.viewportSizeForCSSViewportUnits = m_viewportSizeForCSSViewportUnits;
8060 parameters.scrollPinningBehavior = m_scrollPinningBehavior;
8061 if (m_scrollbarOverlayStyle)
8062 parameters.scrollbarOverlayStyle = m_scrollbarOverlayStyle.value();
8063 else
8064 parameters.scrollbarOverlayStyle = std::nullopt;
8065 parameters.backgroundExtendsBeyondPage = m_backgroundExtendsBeyondPage;
8066 parameters.layerHostingMode = m_layerHostingMode;
8067 parameters.controlledByAutomation = m_controlledByAutomation;
8068 parameters.useDarkAppearance = useDarkAppearance();
8069 parameters.useElevatedUserInterfaceLevel = useElevatedUserInterfaceLevel();
8070#if PLATFORM(MAC)
8071 parameters.colorSpace = pageClient().colorSpace();
8072 parameters.useSystemAppearance = m_useSystemAppearance;
8073#endif
8074
8075#if ENABLE(META_VIEWPORT)
8076 parameters.ignoresViewportScaleLimits = m_forceAlwaysUserScalable;
8077 parameters.viewportConfigurationViewLayoutSize = m_viewportConfigurationViewLayoutSize;
8078 parameters.viewportConfigurationLayoutSizeScaleFactor = m_viewportConfigurationLayoutSizeScaleFactor;
8079 parameters.viewportConfigurationMinimumEffectiveDeviceWidth = m_viewportConfigurationMinimumEffectiveDeviceWidth;
8080 parameters.overrideViewportArguments = m_overrideViewportArguments;
8081#endif
8082
8083#if PLATFORM(IOS_FAMILY)
8084 parameters.screenSize = screenSize();
8085 parameters.availableScreenSize = availableScreenSize();
8086 parameters.overrideScreenSize = overrideScreenSize();
8087 parameters.textAutosizingWidth = textAutosizingWidth();
8088 parameters.mimeTypesWithCustomContentProviders = pageClient().mimeTypesWithCustomContentProviders();
8089 parameters.maximumUnobscuredSize = m_maximumUnobscuredSize;
8090 parameters.deviceOrientation = m_deviceOrientation;
8091 parameters.keyboardIsAttached = isInHardwareKeyboardMode();
8092 parameters.canShowWhileLocked = m_configuration->canShowWhileLocked();
8093#endif
8094
8095#if PLATFORM(COCOA)
8096 parameters.smartInsertDeleteEnabled = m_isSmartInsertDeleteEnabled;
8097 parameters.additionalSupportedImageTypes = m_configuration->additionalSupportedImageTypes();
8098
8099 // Allow microphone access if either preference is set because WebRTC requires microphone access.
8100 bool needWebProcessExtensions = !preferences().useGPUProcessForMediaEnabled()
8101 || !preferences().captureAudioInGPUProcessEnabled()
8102 || !preferences().captureVideoInGPUProcessEnabled();
8103
8104 if (needWebProcessExtensions) {
8105 // FIXME(207716): The following should be removed when the GPU process is complete.
8106 parameters.mediaExtensionHandles = SandboxExtension::createHandlesForMachLookup(mediaRelatedMachServices(), std::nullopt);
8107 parameters.mediaIOKitExtensionHandles = SandboxExtension::createHandlesForIOKitClassExtensions(mediaRelatedIOKitClasses(), std::nullopt);
8108 }
8109
8110 if (!preferences().useGPUProcessForMediaEnabled()
8111 || (!preferences().captureVideoInGPUProcessEnabled() && !preferences().captureVideoInUIProcessEnabled())
8112 || (!preferences().captureAudioInGPUProcessEnabled() && !preferences().captureAudioInUIProcessEnabled())
8113 || !preferences().useGPUProcessForCanvasRenderingEnabled()
8114 || !preferences().useGPUProcessForWebGLEnabled()) {
8115 parameters.gpuIOKitExtensionHandles = SandboxExtension::createHandlesForIOKitClassExtensions(gpuIOKitClasses(), std::nullopt);
8116 parameters.gpuMachExtensionHandles = SandboxExtension::createHandlesForMachLookup(gpuMachServices(), std::nullopt);
8117 }
8118#endif
8119#if HAVE(STATIC_FONT_REGISTRY)
8120 if (preferences().shouldAllowUserInstalledFonts())
8121 parameters.fontMachExtensionHandle = fontdMachExtensionHandle();
8122#endif
8123#if HAVE(APP_ACCENT_COLORS)
8124 parameters.accentColor = pageClient().accentColor();
8125#endif
8126 parameters.shouldScaleViewToFitDocument = m_shouldScaleViewToFitDocument;
8127 parameters.userInterfaceLayoutDirection = pageClient().userInterfaceLayoutDirection();
8128 parameters.observedLayoutMilestones = m_observedLayoutMilestones;
8129 parameters.overrideContentSecurityPolicy = m_overrideContentSecurityPolicy;
8130 parameters.cpuLimit = m_cpuLimit;
8131
8132#if USE(WPE_RENDERER)
8133 parameters.hostFileDescriptor = pageClient().hostFileDescriptor();
8134#endif
8135
8136#if PLATFORM(WIN)
8137 parameters.nativeWindowHandle = reinterpret_cast<uint64_t>(viewWidget());
8138#endif
8139
8140 for (auto& iterator : m_urlSchemeHandlersByScheme)
8141 parameters.urlSchemeHandlers.set(iterator.key, iterator.value->identifier());
8142 parameters.urlSchemesWithLegacyCustomProtocolHandlers = WebProcessPool::urlSchemesWithCustomProtocolHandlers();
8143
8144#if ENABLE(WEB_RTC)
8145 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8146 parameters.iceCandidateFilteringEnabled = m_preferences->iceCandidateFilteringEnabled();
8147#if USE(LIBWEBRTC)
8148 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8149 parameters.enumeratingAllNetworkInterfacesEnabled = m_preferences->enumeratingAllNetworkInterfacesEnabled();
8150#endif
8151#endif
8152
8153#if ENABLE(APPLICATION_MANIFEST)
8154 parameters.applicationManifest = m_configuration->applicationManifest() ? std::optional<WebCore::ApplicationManifest>(m_configuration->applicationManifest()->applicationManifest()) : std::nullopt;
8155#endif
8156
8157 parameters.needsFontAttributes = m_needsFontAttributes;
8158 parameters.backgroundColor = m_backgroundColor;
8159
8160 parameters.overriddenMediaType = m_overriddenMediaType;
8161 parameters.corsDisablingPatterns = corsDisablingPatterns();
8162 parameters.userScriptsShouldWaitUntilNotification = m_configuration->userScriptsShouldWaitUntilNotification();
8163 parameters.allowedNetworkHosts = m_configuration->allowedNetworkHosts();
8164 parameters.loadsSubresources = m_configuration->loadsSubresources();
8165 parameters.crossOriginAccessControlCheckEnabled = m_configuration->crossOriginAccessControlCheckEnabled();
8166 parameters.hasResourceLoadClient = !!m_resourceLoadClient;
8167
8168 std::reference_wrapper<WebUserContentControllerProxy> userContentController(m_userContentController.get());
8169 if (auto* userContentControllerFromWebsitePolicies = websitePolicies ? websitePolicies->userContentController() : nullptr)
8170 userContentController = *userContentControllerFromWebsitePolicies;
8171 process.addWebUserContentControllerProxy(userContentController);
8172 parameters.userContentControllerParameters = userContentController.get().parameters();
8173
8174 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8175 parameters.shouldCaptureAudioInUIProcess = preferences().captureAudioInUIProcessEnabled();
8176 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8177 parameters.shouldCaptureAudioInGPUProcess = preferences().captureAudioInGPUProcessEnabled();
8178 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8179 parameters.shouldCaptureVideoInUIProcess = preferences().captureVideoInUIProcessEnabled();
8180 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8181 parameters.shouldCaptureVideoInGPUProcess = preferences().captureVideoInGPUProcessEnabled();
8182 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8183 parameters.shouldRenderCanvasInGPUProcess = preferences().useGPUProcessForCanvasRenderingEnabled();
8184 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8185 parameters.shouldRenderDOMInGPUProcess = preferences().useGPUProcessForDOMRenderingEnabled();
8186 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8187 parameters.shouldPlayMediaInGPUProcess = preferences().useGPUProcessForMediaEnabled();
8188#if ENABLE(WEBGL)
8189 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8190 parameters.shouldRenderWebGLInGPUProcess = preferences().useGPUProcessForWebGLEnabled();
8191#endif
8192
8193 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8194 parameters.shouldEnableVP9Decoder = preferences().vp9DecoderEnabled();
8195#if ENABLE(VP9) && PLATFORM(COCOA)
8196 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8197 parameters.shouldEnableVP8Decoder = preferences().vp9DecoderEnabled();
8198 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8199 parameters.shouldEnableVP9SWDecoder = preferences().vp9DecoderEnabled() && (!WebCore::systemHasBattery() || preferences().vp9SWDecoderEnabledOnBattery());
8200#endif
8201 parameters.shouldCaptureDisplayInUIProcess = m_process->processPool().configuration().shouldCaptureDisplayInUIProcess();
8202#if ENABLE(APP_BOUND_DOMAINS)
8203 parameters.limitsNavigationsToAppBoundDomains = m_limitsNavigationsToAppBoundDomains;
8204#endif
8205 parameters.lastNavigationWasAppBound = m_lastNavigationWasAppBound;
8206 parameters.shouldRelaxThirdPartyCookieBlocking = m_configuration->shouldRelaxThirdPartyCookieBlocking();
8207 parameters.canUseCredentialStorage = m_canUseCredentialStorage;
8208
8209#if PLATFORM(GTK)
8210 parameters.themeName = pageClient().themeName();
8211#endif
8212
8213#if ENABLE(ATTACHMENT_ELEMENT) && PLATFORM(COCOA)
8214 if (m_preferences->attachmentElementEnabled() && !process.hasIssuedAttachmentElementRelatedSandboxExtensions()) {
8215 parameters.attachmentElementExtensionHandles = SandboxExtension::createHandlesForMachLookup(attachmentElementServices(), std::nullopt);
8216 process.setHasIssuedAttachmentElementRelatedSandboxExtensions();
8217 }
8218#endif
8219
8220 parameters.httpsUpgradeEnabled = preferences().upgradeKnownHostsToHTTPSEnabled() ? m_configuration->httpsUpgradeEnabled() : false;
8221
8222#if PLATFORM(IOS)
8223 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8224 parameters.allowsDeprecatedSynchronousXMLHttpRequestDuringUnload = allowsDeprecatedSynchronousXMLHttpRequestDuringUnload();
8225#endif
8226
8227#if ENABLE(APP_HIGHLIGHTS)
8228 parameters.appHighlightsVisible = appHighlightsVisibility() ? HighlightVisibility::Visible : HighlightVisibility::Hidden;
8229#endif
8230
8231 return parameters;
8232}
8233
8234void WebPageProxy::isJITEnabled(CompletionHandler<void(bool)>&& completionHandler)
8235{
8236 sendWithAsyncReply(Messages::WebProcess::IsJITEnabled(), WTFMove(completionHandler), 0);
8237}
8238
8239void WebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
8240{
8241#if PLATFORM(MAC)
8242 ASSERT(m_drawingArea->type() == DrawingAreaTypeTiledCoreAnimation);
8243#endif
8244 pageClient().enterAcceleratedCompositingMode(layerTreeContext);
8245}
8246
8247void WebPageProxy::didFirstLayerFlush(const LayerTreeContext& layerTreeContext)
8248{
8249#if PLATFORM(MAC)
8250 ASSERT(m_drawingArea->type() == DrawingAreaTypeTiledCoreAnimation);
8251#endif
8252 pageClient().didFirstLayerFlush(layerTreeContext);
8253
8254 if (m_lastSuspendedPage)
8255 m_lastSuspendedPage->pageDidFirstLayerFlush();
8256 m_suspendedPageKeptToPreventFlashing = nullptr;
8257}
8258
8259void WebPageProxy::exitAcceleratedCompositingMode()
8260{
8261 pageClient().exitAcceleratedCompositingMode();
8262}
8263
8264void WebPageProxy::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
8265{
8266 pageClient().updateAcceleratedCompositingMode(layerTreeContext);
8267}
8268
8269void WebPageProxy::backForwardClear()
8270{
8271 m_backForwardList->clear();
8272}
8273
8274#if ENABLE(GAMEPAD)
8275
8276void WebPageProxy::gamepadActivity(const Vector<GamepadData>& gamepadDatas, EventMakesGamepadsVisible eventVisibility)
8277{
8278 send(Messages::WebPage::GamepadActivity(gamepadDatas, eventVisibility));
8279}
8280
8281#endif
8282
8283void WebPageProxy::didReceiveAuthenticationChallengeProxy(Ref<AuthenticationChallengeProxy>&& authenticationChallenge, NegotiatedLegacyTLS negotiatedLegacyTLS)
8284{
8285 if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes) {
8286 m_navigationClient->shouldAllowLegacyTLS(*this, authenticationChallenge.get(), [this, protectedThis = makeRef(*this), authenticationChallenge] (bool shouldAllowLegacyTLS) {
8287 if (shouldAllowLegacyTLS)
8288 m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get());
8289 else
8290 authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::Cancel);
8291 });
8292 return;
8293 }
8294 m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get());
8295}
8296
8297void WebPageProxy::negotiatedLegacyTLS()
8298{
8299 auto transaction = m_pageLoadState.transaction();
8300 m_pageLoadState.negotiatedLegacyTLS(transaction);
8301}
8302
8303void WebPageProxy::didNegotiateModernTLS(const URL& url)
8304{
8305 m_navigationClient->didNegotiateModernTLS(url);
8306}
8307
8308void WebPageProxy::exceededDatabaseQuota(FrameIdentifier frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply&& reply)
8309{
8310 requestStorageSpace(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [reply = WTFMove(reply)](auto quota) mutable {
8311 reply(quota);
8312 });
8313}
8314
8315void WebPageProxy::requestStorageSpace(FrameIdentifier frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, CompletionHandler<void(uint64_t)>&& completionHandler)
8316{
8317 WEBPAGEPROXY_RELEASE_LOG(Storage, "requestStorageSpace for frame %" PRIu64 ", current quota %" PRIu64 " current usage %" PRIu64 " expected usage %" PRIu64, frameID.toUInt64(), currentQuota, currentDatabaseUsage, expectedUsage);
8318
8319 StorageRequests::singleton().processOrAppend([this, protectedThis = makeRef(*this), pageURL = currentURL(), frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, completionHandler = WTFMove(completionHandler)]() mutable {
8320 this->makeStorageSpaceRequest(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [this, protectedThis = WTFMove(protectedThis), frameID, pageURL = WTFMove(pageURL), completionHandler = WTFMove(completionHandler), currentQuota](auto quota) mutable {
8321
8322 WEBPAGEPROXY_RELEASE_LOG(Storage, "requestStorageSpace response for frame %" PRIu64 ", quota %" PRIu64, frameID.toUInt64(), quota);
8323 UNUSED_VARIABLE(frameID);
8324
8325 if (quota <= currentQuota && this->currentURL() == pageURL) {
8326 WEBPAGEPROXY_RELEASE_LOG(Storage, "storage space increase denied");
8327 m_isQuotaIncreaseDenied = true;
8328 }
8329 completionHandler(quota);
8330 StorageRequests::singleton().processNextIfAny();
8331 });
8332 });
8333}
8334
8335void WebPageProxy::makeStorageSpaceRequest(FrameIdentifier frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, CompletionHandler<void(uint64_t)>&& completionHandler)
8336{
8337 if (m_isQuotaIncreaseDenied) {
8338 completionHandler(currentQuota);
8339 return;
8340 }
8341
8342 WebFrameProxy* frame = m_process->webFrame(frameID);
8343 MESSAGE_CHECK(m_process, frame);
8344
8345 auto originData = SecurityOriginData::fromDatabaseIdentifier(originIdentifier);
8346 if (originData != SecurityOriginData::fromURL(URL { { }, currentURL() })) {
8347 completionHandler(currentQuota);
8348 return;
8349 }
8350
8351 auto origin = API::SecurityOrigin::create(originData->securityOrigin());
8352 m_uiClient->exceededDatabaseQuota(this, frame, origin.ptr(), databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, WTFMove(completionHandler));
8353}
8354
8355void WebPageProxy::reachedApplicationCacheOriginQuota(const String& originIdentifier, uint64_t currentQuota, uint64_t totalBytesNeeded, Messages::WebPageProxy::ReachedApplicationCacheOriginQuota::DelayedReply&& reply)
8356{
8357 auto securityOriginData = SecurityOriginData::fromDatabaseIdentifier(originIdentifier);
8358 MESSAGE_CHECK(m_process, securityOriginData);
8359
8360 Ref<SecurityOrigin> securityOrigin = securityOriginData->securityOrigin();
8361 m_uiClient->reachedApplicationCacheOriginQuota(this, securityOrigin.get(), currentQuota, totalBytesNeeded, WTFMove(reply));
8362}
8363
8364void WebPageProxy::requestGeolocationPermissionForFrame(GeolocationIdentifier geolocationID, FrameInfoData&& frameInfo)
8365{
8366 MESSAGE_CHECK(m_process, frameInfo.frameID);
8367 auto* frame = m_process->webFrame(*frameInfo.frameID);
8368 MESSAGE_CHECK(m_process, frame);
8369
8370 auto request = m_geolocationPermissionRequestManager.createRequest(geolocationID);
8371 Function<void(bool)> completionHandler = [request = WTFMove(request)](bool allowed) {
8372 if (allowed)
8373 request->allow();
8374 else
8375 request->deny();
8376 };
8377
8378 // FIXME: Once iOS migrates to the new WKUIDelegate SPI, clean this up
8379 // and make it one UIClient call that calls the completionHandler with false
8380 // if there is no delegate instead of returning the completionHandler
8381 // for other code paths to try.
8382 m_uiClient->decidePolicyForGeolocationPermissionRequest(*this, *frame, frameInfo, completionHandler);
8383#if PLATFORM(IOS_FAMILY)
8384 if (completionHandler)
8385 pageClient().decidePolicyForGeolocationPermissionRequest(*frame, frameInfo, completionHandler);
8386#endif
8387 if (completionHandler)
8388 completionHandler(false);
8389}
8390
8391void WebPageProxy::revokeGeolocationAuthorizationToken(const String& authorizationToken)
8392{
8393 m_geolocationPermissionRequestManager.revokeAuthorizationToken(authorizationToken);
8394}
8395
8396#if ENABLE(MEDIA_STREAM)
8397UserMediaPermissionRequestManagerProxy& WebPageProxy::userMediaPermissionRequestManager()
8398{
8399 if (m_userMediaPermissionRequestManager)
8400 return *m_userMediaPermissionRequestManager;
8401
8402 m_userMediaPermissionRequestManager = makeUnique<UserMediaPermissionRequestManagerProxy>(*this);
8403 return *m_userMediaPermissionRequestManager;
8404}
8405
8406void WebPageProxy::setMockCaptureDevicesEnabledOverride(std::optional<bool> enabled)
8407{
8408 userMediaPermissionRequestManager().setMockCaptureDevicesEnabledOverride(enabled);
8409}
8410
8411void WebPageProxy::willStartCapture(const UserMediaPermissionRequestProxy& request, CompletionHandler<void()>&& callback)
8412{
8413#if ENABLE(GPU_PROCESS)
8414 if (!preferences().captureVideoInGPUProcessEnabled() && !preferences().captureAudioInGPUProcessEnabled())
8415 return callback();
8416
8417 auto& gpuProcess = process().processPool().ensureGPUProcess();
8418 gpuProcess.updateCaptureAccess(request.requiresAudioCapture(), request.requiresVideoCapture(), request.requiresDisplayCapture(), m_process->coreProcessIdentifier(), WTFMove(callback));
8419#if PLATFORM(IOS_FAMILY)
8420 gpuProcess.setOrientationForMediaCapture(m_deviceOrientation);
8421#endif
8422#else
8423 callback();
8424#endif
8425}
8426
8427#endif
8428
8429void WebPageProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, FrameIdentifier frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData, WebCore::MediaStreamRequest&& request)
8430{
8431#if ENABLE(MEDIA_STREAM)
8432 MESSAGE_CHECK(m_process, m_process->webFrame(frameID));
8433
8434 userMediaPermissionRequestManager().requestUserMediaPermissionForFrame(userMediaID, frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin(), WTFMove(request));
8435#else
8436 UNUSED_PARAM(userMediaID);
8437 UNUSED_PARAM(frameID);
8438 UNUSED_PARAM(userMediaDocumentOriginData);
8439 UNUSED_PARAM(topLevelDocumentOriginData);
8440 UNUSED_PARAM(request);
8441#endif
8442}
8443
8444void WebPageProxy::enumerateMediaDevicesForFrame(FrameIdentifier frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData, CompletionHandler<void(const Vector<CaptureDevice>&, const String&)>&& completionHandler)
8445{
8446#if ENABLE(MEDIA_STREAM)
8447 WebFrameProxy* frame = m_process->webFrame(frameID);
8448 MESSAGE_CHECK(m_process, frame);
8449
8450 userMediaPermissionRequestManager().enumerateMediaDevicesForFrame(frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin(), WTFMove(completionHandler));
8451#else
8452 UNUSED_PARAM(frameID);
8453 UNUSED_PARAM(userMediaDocumentOriginData);
8454 UNUSED_PARAM(topLevelDocumentOriginData);
8455 UNUSED_PARAM(completionHandler);
8456#endif
8457}
8458
8459void WebPageProxy::syncIfMockDevicesEnabledChanged()
8460{
8461#if ENABLE(MEDIA_STREAM)
8462 userMediaPermissionRequestManager().syncWithWebCorePrefs();
8463#endif
8464}
8465
8466void WebPageProxy::beginMonitoringCaptureDevices()
8467{
8468#if ENABLE(MEDIA_STREAM)
8469 userMediaPermissionRequestManager().syncWithWebCorePrefs();
8470 UserMediaProcessManager::singleton().beginMonitoringCaptureDevices();
8471#endif
8472}
8473
8474void WebPageProxy::clearUserMediaState()
8475{
8476#if ENABLE(MEDIA_STREAM)
8477 if (m_userMediaPermissionRequestManager)
8478 m_userMediaPermissionRequestManager->clearCachedState();
8479#endif
8480}
8481
8482void WebPageProxy::requestMediaKeySystemPermissionForFrame(uint64_t mediaKeySystemID, FrameIdentifier frameID, const WebCore::SecurityOriginData& topLevelDocumentOriginData, const String& keySystem)
8483{
8484#if ENABLE(ENCRYPTED_MEDIA)
8485 MESSAGE_CHECK(m_process, m_process->webFrame(frameID));
8486
8487 auto origin = API::SecurityOrigin::create(topLevelDocumentOriginData.securityOrigin());
8488 auto request = mediaKeySystemPermissionRequestManager().createRequestForFrame(mediaKeySystemID, frameID, topLevelDocumentOriginData.securityOrigin(), keySystem);
8489 m_uiClient->decidePolicyForMediaKeySystemPermissionRequest(*this, origin, keySystem, [request = WTFMove(request)](bool allowed) {
8490 if (allowed)
8491 request->allow();
8492 else
8493 request->deny();
8494 });
8495#else
8496 UNUSED_PARAM(mediaKeySystemID);
8497 UNUSED_PARAM(frameID);
8498 UNUSED_PARAM(topLevelDocumentOriginData);
8499 UNUSED_PARAM(keySystem);
8500#endif
8501}
8502
8503#if ENABLE(DEVICE_ORIENTATION)
8504void WebPageProxy::shouldAllowDeviceOrientationAndMotionAccess(FrameIdentifier frameID, FrameInfoData&& frameInfo, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& completionHandler)
8505{
8506 WebFrameProxy* frame = m_process->webFrame(frameID);
8507 MESSAGE_CHECK(m_process, frame);
8508
8509 websiteDataStore().deviceOrientationAndMotionAccessController().shouldAllowAccess(*this, *frame, WTFMove(frameInfo), mayPrompt, WTFMove(completionHandler));
8510}
8511#endif
8512
8513
8514#if ENABLE(IMAGE_ANALYSIS)
8515
8516void WebPageProxy::requestTextRecognition(const URL& imageURL, const ShareableBitmap::Handle& imageData, CompletionHandler<void(WebCore::TextRecognitionResult&&)>&& completionHandler)
8517{
8518 pageClient().requestTextRecognition(imageURL, imageData, WTFMove(completionHandler));
8519}
8520
8521void WebPageProxy::computeHasImageAnalysisResults(const URL& imageURL, ShareableBitmap& imageBitmap, ImageAnalysisType type, CompletionHandler<void(bool)>&& completion)
8522{
8523 pageClient().computeHasImageAnalysisResults(imageURL, imageBitmap, type, WTFMove(completion));
8524}
8525
8526void WebPageProxy::updateWithTextRecognitionResult(TextRecognitionResult&& results, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(TextRecognitionUpdateResult)>&& completionHandler)
8527{
8528 if (!hasRunningProcess()) {
8529 completionHandler(TextRecognitionUpdateResult::NoText);
8530 return;
8531 }
8532
8533 sendWithAsyncReply(Messages::WebPage::UpdateWithTextRecognitionResult(WTFMove(results), context, location), WTFMove(completionHandler));
8534}
8535
8536#endif // ENABLE(IMAGE_ANALYSIS)
8537
8538#if ENABLE(ENCRYPTED_MEDIA)
8539MediaKeySystemPermissionRequestManagerProxy& WebPageProxy::mediaKeySystemPermissionRequestManager()
8540{
8541 if (m_mediaKeySystemPermissionRequestManager)
8542 return *m_mediaKeySystemPermissionRequestManager;
8543
8544 m_mediaKeySystemPermissionRequestManager = makeUnique<MediaKeySystemPermissionRequestManagerProxy>(*this);
8545 return *m_mediaKeySystemPermissionRequestManager;
8546}
8547#endif
8548
8549#if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
8550
8551void WebPageProxy::showMediaControlsContextMenu(FloatRect&& targetFrame, Vector<MediaControlsContextMenuItem>&& items, CompletionHandler<void(MediaControlsContextMenuItem::ID)>&& completionHandler)
8552{
8553 pageClient().showMediaControlsContextMenu(WTFMove(targetFrame), WTFMove(items), WTFMove(completionHandler));
8554}
8555
8556#endif // ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
8557
8558
8559void WebPageProxy::requestNotificationPermission(const String& originString, CompletionHandler<void(bool allowed)>&& completionHandler)
8560{
8561 auto origin = API::SecurityOrigin::createFromString(originString);
8562 m_uiClient->decidePolicyForNotificationPermissionRequest(*this, origin.get(), WTFMove(completionHandler));
8563}
8564
8565void WebPageProxy::showNotification(const String& title, const String& body, const String& iconURL, const String& tag, const String& lang, WebCore::NotificationDirection dir, const String& originString, uint64_t notificationID)
8566{
8567 m_process->processPool().supplement<WebNotificationManagerProxy>()->show(this, title, body, iconURL, tag, lang, dir, originString, notificationID);
8568}
8569
8570void WebPageProxy::cancelNotification(uint64_t notificationID)
8571{
8572 m_process->processPool().supplement<WebNotificationManagerProxy>()->cancel(this, notificationID);
8573}
8574
8575void WebPageProxy::clearNotifications(const Vector<uint64_t>& notificationIDs)
8576{
8577 m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this, notificationIDs);
8578}
8579
8580void WebPageProxy::didDestroyNotification(uint64_t notificationID)
8581{
8582 m_process->processPool().supplement<WebNotificationManagerProxy>()->didDestroyNotification(this, notificationID);
8583}
8584
8585float WebPageProxy::headerHeight(WebFrameProxy& frame)
8586{
8587 if (frame.isDisplayingPDFDocument())
8588 return 0;
8589 return m_uiClient->headerHeight(*this, frame);
8590}
8591
8592float WebPageProxy::footerHeight(WebFrameProxy& frame)
8593{
8594 if (frame.isDisplayingPDFDocument())
8595 return 0;
8596 return m_uiClient->footerHeight(*this, frame);
8597}
8598
8599void WebPageProxy::drawHeader(WebFrameProxy& frame, FloatRect&& rect)
8600{
8601 if (frame.isDisplayingPDFDocument())
8602 return;
8603 m_uiClient->drawHeader(*this, frame, WTFMove(rect));
8604}
8605
8606void WebPageProxy::drawFooter(WebFrameProxy& frame, FloatRect&& rect)
8607{
8608 if (frame.isDisplayingPDFDocument())
8609 return;
8610 m_uiClient->drawFooter(*this, frame, WTFMove(rect));
8611}
8612
8613void WebPageProxy::runModal()
8614{
8615 // Since runModal() can (and probably will) spin a nested run loop we need to turn off the responsiveness timer.
8616 m_process->stopResponsivenessTimer();
8617
8618 // Our Connection's run loop might have more messages waiting to be handled after this RunModal message.
8619 // To make sure they are handled inside of the nested modal run loop we must first signal the Connection's
8620 // run loop so we're guaranteed that it has a chance to wake up.
8621 // See http://webkit.org/b/89590 for more discussion.
8622 m_process->connection()->wakeUpRunLoop();
8623
8624 m_uiClient->runModal(*this);
8625}
8626
8627void WebPageProxy::notifyScrollerThumbIsVisibleInRect(const IntRect& scrollerThumb)
8628{
8629 m_visibleScrollerThumbRect = scrollerThumb;
8630}
8631
8632void WebPageProxy::recommendedScrollbarStyleDidChange(int32_t newStyle)
8633{
8634#if USE(APPKIT)
8635 pageClient().recommendedScrollbarStyleDidChange(static_cast<WebCore::ScrollbarStyle>(newStyle));
8636#else
8637 UNUSED_PARAM(newStyle);
8638#endif
8639}
8640
8641void WebPageProxy::didChangeScrollbarsForMainFrame(bool hasHorizontalScrollbar, bool hasVerticalScrollbar)
8642{
8643 m_mainFrameHasHorizontalScrollbar = hasHorizontalScrollbar;
8644 m_mainFrameHasVerticalScrollbar = hasVerticalScrollbar;
8645}
8646
8647void WebPageProxy::didChangeScrollOffsetPinningForMainFrame(bool pinnedToLeftSide, bool pinnedToRightSide, bool pinnedToTopSide, bool pinnedToBottomSide)
8648{
8649 pageClient().pinnedStateWillChange();
8650 m_mainFrameIsPinnedToLeftSide = pinnedToLeftSide;
8651 m_mainFrameIsPinnedToRightSide = pinnedToRightSide;
8652 m_mainFrameIsPinnedToTopSide = pinnedToTopSide;
8653 m_mainFrameIsPinnedToBottomSide = pinnedToBottomSide;
8654 pageClient().pinnedStateDidChange();
8655
8656 m_uiClient->pinnedStateDidChange(*this);
8657}
8658
8659void WebPageProxy::didChangePageCount(unsigned pageCount)
8660{
8661 m_pageCount = pageCount;
8662}
8663
8664void WebPageProxy::themeColorChanged(const Color& themeColor)
8665{
8666 if (m_themeColor == themeColor)
8667 return;
8668
8669 pageClient().themeColorWillChange();
8670 m_themeColor = themeColor;
8671 pageClient().themeColorDidChange();
8672}
8673
8674void WebPageProxy::pageExtendedBackgroundColorDidChange(const Color& newPageExtendedBackgroundColor)
8675{
8676 if (m_pageExtendedBackgroundColor == newPageExtendedBackgroundColor)
8677 return;
8678
8679 auto oldUnderPageBackgroundColor = underPageBackgroundColor();
8680 auto oldPageExtendedBackgroundColor = std::exchange(m_pageExtendedBackgroundColor, newPageExtendedBackgroundColor);
8681 bool changesUnderPageBackgroundColor = !equalIgnoringSemanticColor(oldUnderPageBackgroundColor, underPageBackgroundColor());
8682 m_pageExtendedBackgroundColor = WTFMove(oldPageExtendedBackgroundColor);
8683
8684 if (changesUnderPageBackgroundColor)
8685 pageClient().underPageBackgroundColorWillChange();
8686 pageClient().pageExtendedBackgroundColorWillChange();
8687
8688 m_pageExtendedBackgroundColor = newPageExtendedBackgroundColor;
8689
8690 if (changesUnderPageBackgroundColor)
8691 pageClient().underPageBackgroundColorDidChange();
8692 pageClient().pageExtendedBackgroundColorDidChange();
8693}
8694
8695void WebPageProxy::sampledPageTopColorChanged(const Color& sampledPageTopColor)
8696{
8697 if (m_sampledPageTopColor == sampledPageTopColor)
8698 return;
8699
8700 pageClient().sampledPageTopColorWillChange();
8701 m_sampledPageTopColor = sampledPageTopColor;
8702 pageClient().sampledPageTopColorDidChange();
8703}
8704
8705#if !PLATFORM(COCOA)
8706
8707Color WebPageProxy::platformUnderPageBackgroundColor() const
8708{
8709 return Color::transparentBlack;
8710}
8711
8712#endif // !PLATFORM(COCOA)
8713
8714#if ENABLE(NETSCAPE_PLUGIN_API)
8715void WebPageProxy::didFailToInitializePlugin(const String& mimeType, const String& frameURLString, const String& pageURLString)
8716{
8717 m_navigationClient->didFailToInitializePlugIn(*this, createPluginInformationDictionary(mimeType, frameURLString, pageURLString).get());
8718}
8719
8720void WebPageProxy::didBlockInsecurePluginVersion(const String& mimeType, const String& pluginURLString, const String& frameURLString, const String& pageURLString, bool replacementObscured)
8721{
8722 String newMimeType = mimeType;
8723 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString));
8724 auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, mimeType, pageURLString, String(), String(), replacementObscured);
8725
8726 m_navigationClient->didBlockInsecurePluginVersion(*this, pluginInformation.get());
8727}
8728#endif // ENABLE(NETSCAPE_PLUGIN_API)
8729
8730bool WebPageProxy::willHandleHorizontalScrollEvents() const
8731{
8732 return !m_canShortCircuitHorizontalWheelEvents;
8733}
8734
8735void WebPageProxy::updateWebsitePolicies(WebsitePoliciesData&& websitePolicies)
8736{
8737 send(Messages::WebPage::UpdateWebsitePolicies(websitePolicies));
8738}
8739
8740void WebPageProxy::notifyUserScripts()
8741{
8742 m_userScriptsNotified = true;
8743 send(Messages::WebPage::NotifyUserScripts());
8744}
8745
8746bool WebPageProxy::userScriptsNeedNotification() const
8747{
8748 if (!m_configuration->userScriptsShouldWaitUntilNotification())
8749 return false;
8750 return !m_userScriptsNotified;
8751}
8752
8753void WebPageProxy::didFinishLoadingDataForCustomContentProvider(const String& suggestedFilename, const IPC::DataReference& dataReference)
8754{
8755 pageClient().didFinishLoadingDataForCustomContentProvider(ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), dataReference);
8756}
8757
8758void WebPageProxy::backForwardRemovedItem(const BackForwardItemIdentifier& itemID)
8759{
8760 send(Messages::WebPage::DidRemoveBackForwardItem(itemID));
8761}
8762
8763void WebPageProxy::setCanRunModal(bool canRunModal)
8764{
8765 // It's only possible to change the state for a WebPage which
8766 // already qualifies for running modal child web pages, otherwise
8767 // there's no other possibility than not allowing it.
8768 m_canRunModal = m_uiClient->canRunModal() && canRunModal;
8769
8770 if (!hasRunningProcess())
8771 return;
8772
8773 send(Messages::WebPage::SetCanRunModal(m_canRunModal));
8774}
8775
8776bool WebPageProxy::canRunModal()
8777{
8778 return hasRunningProcess() ? m_canRunModal : false;
8779}
8780
8781void WebPageProxy::beginPrinting(WebFrameProxy* frame, const PrintInfo& printInfo)
8782{
8783 if (m_isInPrintingMode)
8784 return;
8785
8786 m_isInPrintingMode = true;
8787 send(Messages::WebPage::BeginPrinting(frame->frameID(), printInfo), printingSendOptions(m_isPerformingDOMPrintOperation));
8788}
8789
8790void WebPageProxy::endPrinting()
8791{
8792 if (!m_isInPrintingMode)
8793 return;
8794
8795 m_isInPrintingMode = false;
8796 send(Messages::WebPage::EndPrinting(), printingSendOptions(m_isPerformingDOMPrintOperation));
8797}
8798
8799uint64_t WebPageProxy::computePagesForPrinting(WebFrameProxy* frame, const PrintInfo& printInfo, CompletionHandler<void(const Vector<WebCore::IntRect>&, double, const WebCore::FloatBoxExtent&)>&& callback)
8800{
8801 m_isInPrintingMode = true;
8802 return sendWithAsyncReply(Messages::WebPage::ComputePagesForPrinting(frame->frameID(), printInfo), WTFMove(callback), printingSendOptions(m_isPerformingDOMPrintOperation));
8803}
8804
8805#if PLATFORM(COCOA)
8806uint64_t WebPageProxy::drawRectToImage(WebFrameProxy* frame, const PrintInfo& printInfo, const IntRect& rect, const WebCore::IntSize& imageSize, CompletionHandler<void(const WebKit::ShareableBitmap::Handle&)>&& callback)
8807{
8808 return sendWithAsyncReply(Messages::WebPage::DrawRectToImage(frame->frameID(), printInfo, rect, imageSize), WTFMove(callback), printingSendOptions(m_isPerformingDOMPrintOperation));
8809}
8810
8811uint64_t WebPageProxy::drawPagesToPDF(WebFrameProxy* frame, const PrintInfo& printInfo, uint32_t first, uint32_t count, CompletionHandler<void(API::Data*)>&& callback)
8812{
8813 return sendWithAsyncReply(Messages::WebPage::DrawPagesToPDF(frame->frameID(), printInfo, first, count), toAPIDataCallback(WTFMove(callback)), printingSendOptions(m_isPerformingDOMPrintOperation));
8814}
8815#elif PLATFORM(GTK)
8816void WebPageProxy::drawPagesForPrinting(WebFrameProxy* frame, const PrintInfo& printInfo, CompletionHandler<void(API::Error*)>&& callback)
8817{
8818 auto callbackWrapper = [callback = WTFMove(callback)] (const WebCore::ResourceError& error) mutable {
8819 if (error.isNull())
8820 return callback(nullptr);
8821 callback(API::Error::create(error).ptr());
8822 };
8823 m_isInPrintingMode = true;
8824 sendWithAsyncReply(Messages::WebPage::DrawPagesForPrinting(frame->frameID(), printInfo), WTFMove(callbackWrapper), printingSendOptions(m_isPerformingDOMPrintOperation));
8825}
8826#endif
8827
8828#if PLATFORM(COCOA)
8829void WebPageProxy::drawToPDF(FrameIdentifier frameID, const std::optional<FloatRect>& rect, CompletionHandler<void(const IPC::DataReference&)>&& callback)
8830{
8831 if (!hasRunningProcess()) {
8832 callback({ });
8833 return;
8834 }
8835 sendWithAsyncReply(Messages::WebPage::DrawToPDF(frameID, rect), WTFMove(callback));
8836}
8837#endif // PLATFORM(COCOA)
8838
8839void WebPageProxy::getPDFFirstPageSize(WebCore::FrameIdentifier frameID, CompletionHandler<void(WebCore::FloatSize)>&& completionHandler)
8840{
8841 sendWithAsyncReply(Messages::WebPage::GetPDFFirstPageSize(frameID), WTFMove(completionHandler));
8842}
8843
8844void WebPageProxy::updateBackingStoreDiscardableState()
8845{
8846 ASSERT(hasRunningProcess());
8847
8848 if (!m_drawingArea)
8849 return;
8850
8851 bool isDiscardable;
8852
8853 if (!m_process->isResponsive())
8854 isDiscardable = false;
8855 else
8856 isDiscardable = !pageClient().isViewWindowActive() || !isViewVisible();
8857
8858 m_drawingArea->setBackingStoreIsDiscardable(isDiscardable);
8859}
8860
8861void WebPageProxy::saveDataToFileInDownloadsFolder(String&& suggestedFilename, String&& mimeType, URL&& originatingURLString, API::Data& data)
8862{
8863 m_uiClient->saveDataToFileInDownloadsFolder(this, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), mimeType, originatingURLString, data);
8864}
8865
8866void WebPageProxy::savePDFToFileInDownloadsFolder(String&& suggestedFilename, URL&& originatingURL, const IPC::DataReference& dataReference)
8867{
8868 String sanitizedFilename = ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename);
8869 if (!sanitizedFilename.endsWithIgnoringASCIICase(".pdf"))
8870 return;
8871
8872 saveDataToFileInDownloadsFolder(WTFMove(sanitizedFilename), "application/pdf"_s, WTFMove(originatingURL),
8873 API::Data::create(dataReference.data(), dataReference.size()).get());
8874}
8875
8876void WebPageProxy::setMinimumSizeForAutoLayout(const IntSize& size)
8877{
8878 if (m_minimumSizeForAutoLayout == size)
8879 return;
8880
8881 m_minimumSizeForAutoLayout = size;
8882
8883 if (!hasRunningProcess())
8884 return;
8885
8886 send(Messages::WebPage::SetMinimumSizeForAutoLayout(size));
8887 m_drawingArea->minimumSizeForAutoLayoutDidChange();
8888
8889#if USE(APPKIT)
8890 if (m_minimumSizeForAutoLayout.width() <= 0)
8891 didChangeIntrinsicContentSize(IntSize(-1, -1));
8892#endif
8893}
8894
8895void WebPageProxy::setSizeToContentAutoSizeMaximumSize(const IntSize& size)
8896{
8897 if (m_sizeToContentAutoSizeMaximumSize == size)
8898 return;
8899
8900 m_sizeToContentAutoSizeMaximumSize = size;
8901
8902 if (!hasRunningProcess())
8903 return;
8904
8905 send(Messages::WebPage::SetSizeToContentAutoSizeMaximumSize(size));
8906 m_drawingArea->sizeToContentAutoSizeMaximumSizeDidChange();
8907
8908#if USE(APPKIT)
8909 if (m_sizeToContentAutoSizeMaximumSize.width() <= 0)
8910 didChangeIntrinsicContentSize(IntSize(-1, -1));
8911#endif
8912}
8913
8914void WebPageProxy::setAutoSizingShouldExpandToViewHeight(bool shouldExpand)
8915{
8916 if (m_autoSizingShouldExpandToViewHeight == shouldExpand)
8917 return;
8918
8919 m_autoSizingShouldExpandToViewHeight = shouldExpand;
8920
8921 if (!hasRunningProcess())
8922 return;
8923
8924 send(Messages::WebPage::SetAutoSizingShouldExpandToViewHeight(shouldExpand));
8925}
8926
8927void WebPageProxy::setViewportSizeForCSSViewportUnits(const IntSize& viewportSize)
8928{
8929 if (m_viewportSizeForCSSViewportUnits && *m_viewportSizeForCSSViewportUnits == viewportSize)
8930 return;
8931
8932 m_viewportSizeForCSSViewportUnits = viewportSize;
8933
8934 if (!hasRunningProcess())
8935 return;
8936
8937 send(Messages::WebPage::SetViewportSizeForCSSViewportUnits(viewportSize));
8938}
8939
8940#if USE(AUTOMATIC_TEXT_REPLACEMENT)
8941
8942void WebPageProxy::toggleSmartInsertDelete()
8943{
8944 if (TextChecker::isTestingMode())
8945 TextChecker::setSmartInsertDeleteEnabled(!TextChecker::isSmartInsertDeleteEnabled());
8946}
8947
8948void WebPageProxy::toggleAutomaticQuoteSubstitution()
8949{
8950 if (TextChecker::isTestingMode())
8951 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
8952}
8953
8954void WebPageProxy::toggleAutomaticLinkDetection()
8955{
8956 if (TextChecker::isTestingMode())
8957 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
8958}
8959
8960void WebPageProxy::toggleAutomaticDashSubstitution()
8961{
8962 if (TextChecker::isTestingMode())
8963 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
8964}
8965
8966void WebPageProxy::toggleAutomaticTextReplacement()
8967{
8968 if (TextChecker::isTestingMode())
8969 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
8970}
8971
8972#endif
8973
8974#if USE(DICTATION_ALTERNATIVES)
8975
8976void WebPageProxy::showDictationAlternativeUI(const WebCore::FloatRect& boundingBoxOfDictatedText, WebCore::DictationContext dictationContext)
8977{
8978 pageClient().showDictationAlternativeUI(boundingBoxOfDictatedText, dictationContext);
8979}
8980
8981void WebPageProxy::removeDictationAlternatives(WebCore::DictationContext dictationContext)
8982{
8983 pageClient().removeDictationAlternatives(dictationContext);
8984}
8985
8986void WebPageProxy::dictationAlternatives(WebCore::DictationContext dictationContext, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
8987{
8988 completionHandler(pageClient().dictationAlternatives(dictationContext));
8989}
8990
8991#endif
8992
8993#if PLATFORM(MAC)
8994
8995void WebPageProxy::substitutionsPanelIsShowing(CompletionHandler<void(bool)>&& completionHandler)
8996{
8997 completionHandler(TextChecker::substitutionsPanelIsShowing());
8998}
8999
9000void WebPageProxy::showCorrectionPanel(int32_t panelType, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings)
9001{
9002 // FIXME: Make AlternativeTextType an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9003 pageClient().showCorrectionPanel((AlternativeTextType)panelType, boundingBoxOfReplacedString, replacedString, replacementString, alternativeReplacementStrings);
9004}
9005
9006void WebPageProxy::dismissCorrectionPanel(int32_t reason)
9007{
9008 // FIXME: Make ReasonForDismissingAlternativeText an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9009 pageClient().dismissCorrectionPanel((ReasonForDismissingAlternativeText)reason);
9010}
9011
9012void WebPageProxy::dismissCorrectionPanelSoon(int32_t reason, CompletionHandler<void(String)>&& completionHandler)
9013{
9014 // FIXME: Make ReasonForDismissingAlternativeText an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9015 completionHandler(pageClient().dismissCorrectionPanelSoon((ReasonForDismissingAlternativeText)reason));
9016}
9017
9018void WebPageProxy::recordAutocorrectionResponse(int32_t response, const String& replacedString, const String& replacementString)
9019{
9020 // FIXME: Make AutocorrectionResponse an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9021 pageClient().recordAutocorrectionResponse(static_cast<AutocorrectionResponse>(response), replacedString, replacementString);
9022}
9023
9024void WebPageProxy::handleAlternativeTextUIResult(const String& result)
9025{
9026 if (!isClosed())
9027 send(Messages::WebPage::HandleAlternativeTextUIResult(result));
9028}
9029
9030void WebPageProxy::setEditableElementIsFocused(bool editableElementIsFocused)
9031{
9032 pageClient().setEditableElementIsFocused(editableElementIsFocused);
9033}
9034
9035#endif // PLATFORM(MAC)
9036
9037#if PLATFORM(COCOA) || PLATFORM(GTK)
9038RefPtr<ViewSnapshot> WebPageProxy::takeViewSnapshot(std::optional<WebCore::IntRect>&& clipRect)
9039{
9040 return pageClient().takeViewSnapshot(WTFMove(clipRect));
9041}
9042#endif
9043
9044#if PLATFORM(GTK) || PLATFORM(WPE)
9045void WebPageProxy::cancelComposition(const String& compositionString)
9046{
9047 if (!hasRunningProcess())
9048 return;
9049
9050 // Remove any pending composition key event.
9051 if (m_keyEventQueue.size() > 1) {
9052 auto event = m_keyEventQueue.takeFirst();
9053 m_keyEventQueue.removeAllMatching([](const auto& event) {
9054 return event.handledByInputMethod();
9055 });
9056 m_keyEventQueue.prepend(WTFMove(event));
9057 }
9058 send(Messages::WebPage::CancelComposition(compositionString));
9059}
9060
9061void WebPageProxy::deleteSurrounding(int64_t offset, unsigned characterCount)
9062{
9063 if (!hasRunningProcess())
9064 return;
9065
9066 send(Messages::WebPage::DeleteSurrounding(offset, characterCount));
9067}
9068#endif // PLATFORM(GTK) || PLATFORM(WPE)
9069
9070void WebPageProxy::setScrollPinningBehavior(ScrollPinningBehavior pinning)
9071{
9072 if (m_scrollPinningBehavior == pinning)
9073 return;
9074
9075 m_scrollPinningBehavior = pinning;
9076
9077 if (hasRunningProcess())
9078 send(Messages::WebPage::SetScrollPinningBehavior(pinning));
9079}
9080
9081void WebPageProxy::setOverlayScrollbarStyle(std::optional<WebCore::ScrollbarOverlayStyle> scrollbarStyle)
9082{
9083 if (!m_scrollbarOverlayStyle && !scrollbarStyle)
9084 return;
9085
9086 if ((m_scrollbarOverlayStyle && scrollbarStyle) && m_scrollbarOverlayStyle.value() == scrollbarStyle.value())
9087 return;
9088
9089 m_scrollbarOverlayStyle = scrollbarStyle;
9090
9091 std::optional<uint32_t> scrollbarStyleForMessage;
9092 if (scrollbarStyle)
9093 scrollbarStyleForMessage = static_cast<ScrollbarOverlayStyle>(scrollbarStyle.value());
9094
9095 if (hasRunningProcess())
9096 send(Messages::WebPage::SetScrollbarOverlayStyle(scrollbarStyleForMessage), m_webPageID);
9097}
9098
9099#if ENABLE(WEB_CRYPTO)
9100void WebPageProxy::wrapCryptoKey(const Vector<uint8_t>& key, CompletionHandler<void(bool, Vector<uint8_t>&&)>&& completionHandler)
9101{
9102 PageClientProtector protector(pageClient());
9103
9104 Vector<uint8_t> masterKey;
9105
9106 if (auto keyData = m_navigationClient->webCryptoMasterKey(*this))
9107 masterKey = keyData->dataReference().vector();
9108
9109 Vector<uint8_t> wrappedKey;
9110 bool succeeded = wrapSerializedCryptoKey(masterKey, key, wrappedKey);
9111 completionHandler(succeeded, WTFMove(wrappedKey));
9112}
9113
9114void WebPageProxy::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, CompletionHandler<void(bool, Vector<uint8_t>&&)>&& completionHandler)
9115{
9116 PageClientProtector protector(pageClient());
9117
9118 Vector<uint8_t> masterKey;
9119
9120 if (auto keyData = m_navigationClient->webCryptoMasterKey(*this))
9121 masterKey = keyData->dataReference().vector();
9122
9123 Vector<uint8_t> key;
9124 bool succeeded = unwrapSerializedCryptoKey(masterKey, wrappedKey, key);
9125 completionHandler(succeeded, WTFMove(key));
9126}
9127#endif
9128
9129void WebPageProxy::signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const URL& url, CompletionHandler<void(String)>&& completionHandler)
9130{
9131 PageClientProtector protector(pageClient());
9132
9133 if (auto apiString = m_navigationClient->signedPublicKeyAndChallengeString(*this, keySizeIndex, API::String::create(challengeString), url))
9134 return completionHandler(apiString->string());
9135
9136 completionHandler({ });
9137}
9138
9139void WebPageProxy::addMIMETypeWithCustomContentProvider(const String& mimeType)
9140{
9141 send(Messages::WebPage::AddMIMETypeWithCustomContentProvider(mimeType));
9142}
9143
9144void WebPageProxy::changeFontAttributes(WebCore::FontAttributeChanges&& changes)
9145{
9146 if (!hasRunningProcess())
9147 return;
9148
9149 send(Messages::WebPage::ChangeFontAttributes(WTFMove(changes)));
9150}
9151
9152void WebPageProxy::changeFont(WebCore::FontChanges&& changes)
9153{
9154 if (!hasRunningProcess())
9155 return;
9156
9157 send(Messages::WebPage::ChangeFont(WTFMove(changes)));
9158}
9159
9160// FIXME: Move these functions to WebPageProxyCocoa.mm.
9161#if PLATFORM(COCOA)
9162
9163void WebPageProxy::setTextAsync(const String& text)
9164{
9165 if (hasRunningProcess())
9166 send(Messages::WebPage::SetTextAsync(text));
9167}
9168
9169void WebPageProxy::insertTextAsync(const String& text, const EditingRange& replacementRange, InsertTextOptions&& options)
9170{
9171 if (!hasRunningProcess())
9172 return;
9173
9174 send(Messages::WebPage::InsertTextAsync(text, replacementRange, WTFMove(options)));
9175}
9176
9177void WebPageProxy::hasMarkedText(CompletionHandler<void(bool)>&& callback)
9178{
9179 if (!hasRunningProcess()) {
9180 callback(false);
9181 return;
9182 }
9183 sendWithAsyncReply(Messages::WebPage::HasMarkedText(), WTFMove(callback));
9184}
9185
9186void WebPageProxy::getMarkedRangeAsync(CompletionHandler<void(const EditingRange&)>&& callbackFunction)
9187{
9188 if (!hasRunningProcess()) {
9189 callbackFunction(EditingRange());
9190 return;
9191 }
9192
9193 sendWithAsyncReply(Messages::WebPage::GetMarkedRangeAsync(), WTFMove(callbackFunction));
9194}
9195
9196void WebPageProxy::getSelectedRangeAsync(CompletionHandler<void(const EditingRange&)>&& callbackFunction)
9197{
9198 if (!hasRunningProcess()) {
9199 callbackFunction(EditingRange());
9200 return;
9201 }
9202
9203 sendWithAsyncReply(Messages::WebPage::GetSelectedRangeAsync(), WTFMove(callbackFunction));
9204}
9205
9206void WebPageProxy::characterIndexForPointAsync(const WebCore::IntPoint& point, CompletionHandler<void(uint64_t)>&& callbackFunction)
9207{
9208 sendWithAsyncReply(Messages::WebPage::CharacterIndexForPointAsync(point), WTFMove(callbackFunction));
9209}
9210
9211void WebPageProxy::firstRectForCharacterRangeAsync(const EditingRange& range, CompletionHandler<void(const WebCore::IntRect&, const EditingRange&)>&& callbackFunction)
9212{
9213 if (!hasRunningProcess())
9214 return callbackFunction({ }, { });
9215
9216 sendWithAsyncReply(Messages::WebPage::FirstRectForCharacterRangeAsync(range), WTFMove(callbackFunction));
9217}
9218
9219void WebPageProxy::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const Vector<CompositionHighlight>& highlights, const EditingRange& selectionRange, const EditingRange& replacementRange)
9220{
9221 if (!hasRunningProcess()) {
9222 // If this fails, we should call -discardMarkedText on input context to notify the input method.
9223 // This will happen naturally later, as part of reloading the page.
9224 return;
9225 }
9226
9227 send(Messages::WebPage::SetCompositionAsync(text, underlines, highlights, selectionRange, replacementRange));
9228}
9229
9230void WebPageProxy::confirmCompositionAsync()
9231{
9232 if (!hasRunningProcess())
9233 return;
9234
9235 send(Messages::WebPage::ConfirmCompositionAsync());
9236}
9237
9238void WebPageProxy::setScrollPerformanceDataCollectionEnabled(bool enabled)
9239{
9240 if (enabled == m_scrollPerformanceDataCollectionEnabled)
9241 return;
9242
9243 m_scrollPerformanceDataCollectionEnabled = enabled;
9244
9245 if (m_scrollPerformanceDataCollectionEnabled && !m_scrollingPerformanceData)
9246 m_scrollingPerformanceData = makeUnique<RemoteLayerTreeScrollingPerformanceData>(downcast<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea));
9247 else if (!m_scrollPerformanceDataCollectionEnabled)
9248 m_scrollingPerformanceData = nullptr;
9249}
9250#endif
9251
9252void WebPageProxy::takeSnapshot(IntRect rect, IntSize bitmapSize, SnapshotOptions options, CompletionHandler<void(const ShareableBitmap::Handle&)>&& callback)
9253{
9254 sendWithAsyncReply(Messages::WebPage::TakeSnapshot(rect, bitmapSize, options), WTFMove(callback));
9255}
9256
9257void WebPageProxy::navigationGestureDidBegin()
9258{
9259 PageClientProtector protector(pageClient());
9260
9261 m_isShowingNavigationGestureSnapshot = true;
9262 pageClient().navigationGestureDidBegin();
9263
9264 m_navigationClient->didBeginNavigationGesture(*this);
9265}
9266
9267void WebPageProxy::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
9268{
9269 PageClientProtector protector(pageClient());
9270 if (willNavigate) {
9271 m_isLayerTreeFrozenDueToSwipeAnimation = true;
9272 send(Messages::WebPage::FreezeLayerTreeDueToSwipeAnimation());
9273 }
9274
9275 pageClient().navigationGestureWillEnd(willNavigate, item);
9276
9277 m_navigationClient->willEndNavigationGesture(*this, willNavigate, item);
9278}
9279
9280void WebPageProxy::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
9281{
9282 PageClientProtector protector(pageClient());
9283
9284 pageClient().navigationGestureDidEnd(willNavigate, item);
9285
9286 m_navigationClient->didEndNavigationGesture(*this, willNavigate, item);
9287
9288 if (m_isLayerTreeFrozenDueToSwipeAnimation) {
9289 m_isLayerTreeFrozenDueToSwipeAnimation = false;
9290 send(Messages::WebPage::UnfreezeLayerTreeDueToSwipeAnimation());
9291
9292 if (m_provisionalPage)
9293 m_provisionalPage->unfreezeLayerTreeDueToSwipeAnimation();
9294 }
9295}
9296
9297void WebPageProxy::navigationGestureDidEnd()
9298{
9299 PageClientProtector protector(pageClient());
9300
9301 pageClient().navigationGestureDidEnd();
9302}
9303
9304void WebPageProxy::willRecordNavigationSnapshot(WebBackForwardListItem& item)
9305{
9306 PageClientProtector protector(pageClient());
9307
9308 pageClient().willRecordNavigationSnapshot(item);
9309}
9310
9311void WebPageProxy::navigationGestureSnapshotWasRemoved()
9312{
9313 m_isShowingNavigationGestureSnapshot = false;
9314
9315 // The ViewGestureController may call this method on a WebPageProxy whose view has been destroyed. In such case,
9316 // we need to return early as the pageClient will not be valid below.
9317 if (m_isClosed)
9318 return;
9319
9320 pageClient().didRemoveNavigationGestureSnapshot();
9321
9322 m_navigationClient->didRemoveNavigationGestureSnapshot(*this);
9323}
9324
9325void WebPageProxy::isPlayingMediaDidChange(MediaProducer::MediaStateFlags newState)
9326{
9327#if PLATFORM(IOS_FAMILY)
9328 if (!m_process->throttler().shouldBeRunnable())
9329 return;
9330#endif
9331
9332 if (!m_isClosed)
9333 updatePlayingMediaDidChange(newState, CanDelayNotification::Yes);
9334}
9335
9336void WebPageProxy::updatePlayingMediaDidChange(MediaProducer::MediaStateFlags newState, CanDelayNotification canDelayNotification)
9337{
9338#if ENABLE(MEDIA_STREAM)
9339 auto updateMediaCaptureStateImmediatelyIfNeeded = [&] {
9340 if (canDelayNotification == CanDelayNotification::No && m_updateReportedMediaCaptureStateTimer.isActive()) {
9341 m_updateReportedMediaCaptureStateTimer.stop();
9342 updateReportedMediaCaptureState();
9343 }
9344 };
9345#endif
9346
9347 if (newState == m_mediaState) {
9348#if ENABLE(MEDIA_STREAM)
9349 updateMediaCaptureStateImmediatelyIfNeeded();
9350#endif
9351 return;
9352 }
9353
9354#if PLATFORM(MACCATALYST)
9355 // When the page starts playing media for the first time, make sure we register with
9356 // the EndowmentStateTracker to get notifications when the application is no longer
9357 // user-facing, so that we can appropriately suspend all media playback.
9358 if (!m_isListeningForUserFacingStateChangeNotification) {
9359 EndowmentStateTracker::singleton().addClient(*this);
9360 m_isListeningForUserFacingStateChangeNotification = true;
9361 }
9362#endif
9363
9364#if ENABLE(MEDIA_STREAM)
9365 WebCore::MediaProducer::MediaStateFlags oldMediaCaptureState = m_mediaState & WebCore::MediaProducer::MediaCaptureMask;
9366 WebCore::MediaProducer::MediaStateFlags newMediaCaptureState = newState & WebCore::MediaProducer::MediaCaptureMask;
9367#endif
9368
9369 MediaProducer::MediaStateFlags playingMediaMask { MediaProducer::MediaState::IsPlayingAudio, MediaProducer::MediaState::IsPlayingVideo };
9370 MediaProducer::MediaStateFlags oldState = m_mediaState;
9371
9372 bool playingAudioChanges = (oldState.contains(MediaProducer::MediaState::IsPlayingAudio)) != (newState.contains(MediaProducer::MediaState::IsPlayingAudio));
9373 if (playingAudioChanges)
9374 pageClient().isPlayingAudioWillChange();
9375 m_mediaState = newState;
9376 if (playingAudioChanges)
9377 pageClient().isPlayingAudioDidChange();
9378
9379#if ENABLE(MEDIA_STREAM)
9380 if (oldMediaCaptureState != newMediaCaptureState) {
9381 updateReportedMediaCaptureState();
9382
9383 ASSERT(m_userMediaPermissionRequestManager);
9384 if (m_userMediaPermissionRequestManager)
9385 m_userMediaPermissionRequestManager->captureStateChanged(oldMediaCaptureState, newMediaCaptureState);
9386 }
9387 updateMediaCaptureStateImmediatelyIfNeeded();
9388#endif
9389
9390 activityStateDidChange({ ActivityState::IsAudible, ActivityState::IsCapturingMedia });
9391
9392 playingMediaMask.add(WebCore::MediaProducer::MediaCaptureMask);
9393 if ((oldState & playingMediaMask) != (m_mediaState & playingMediaMask))
9394 m_uiClient->isPlayingMediaDidChange(*this);
9395
9396 if ((oldState.containsAny(MediaProducer::MediaState::HasAudioOrVideo)) != (m_mediaState.containsAny(MediaProducer::MediaState::HasAudioOrVideo)))
9397 videoControlsManagerDidChange();
9398
9399 m_process->updateAudibleMediaAssertions();
9400}
9401
9402void WebPageProxy::updateReportedMediaCaptureState()
9403{
9404 auto activeCaptureState = m_mediaState & MediaProducer::MediaCaptureMask;
9405 if (m_reportedMediaCaptureState == activeCaptureState)
9406 return;
9407
9408 bool haveReportedCapture = m_reportedMediaCaptureState.containsAny(MediaProducer::MediaCaptureMask);
9409 bool willReportCapture = !activeCaptureState.isEmpty();
9410
9411 if (haveReportedCapture && !willReportCapture && m_updateReportedMediaCaptureStateTimer.isActive())
9412 return;
9413
9414 if (!haveReportedCapture && willReportCapture)
9415 m_updateReportedMediaCaptureStateTimer.startOneShot(m_mediaCaptureReportingDelay);
9416
9417 WEBPAGEPROXY_RELEASE_LOG(WebRTC, "updateReportedMediaCaptureState: from %d to %d", m_reportedMediaCaptureState.toRaw(), activeCaptureState.toRaw());
9418
9419 bool microphoneCaptureChanged = (m_reportedMediaCaptureState & MediaProducer::AudioCaptureMask) != (activeCaptureState & MediaProducer::AudioCaptureMask);
9420 bool cameraCaptureChanged = (m_reportedMediaCaptureState & MediaProducer::VideoCaptureMask) != (activeCaptureState & MediaProducer::VideoCaptureMask);
9421
9422 if (microphoneCaptureChanged)
9423 pageClient().microphoneCaptureWillChange();
9424 if (cameraCaptureChanged)
9425 pageClient().cameraCaptureWillChange();
9426
9427 m_reportedMediaCaptureState = activeCaptureState;
9428 m_uiClient->mediaCaptureStateDidChange(m_mediaState);
9429
9430 if (microphoneCaptureChanged)
9431 pageClient().microphoneCaptureChanged();
9432 if (cameraCaptureChanged)
9433 pageClient().cameraCaptureChanged();
9434}
9435
9436void WebPageProxy::videoControlsManagerDidChange()
9437{
9438 pageClient().videoControlsManagerDidChange();
9439}
9440
9441bool WebPageProxy::hasActiveVideoForControlsManager() const
9442{
9443#if ENABLE(VIDEO_PRESENTATION_MODE)
9444 return m_playbackSessionManager && m_playbackSessionManager->controlsManagerInterface();
9445#else
9446 return false;
9447#endif
9448}
9449
9450void WebPageProxy::requestControlledElementID() const
9451{
9452#if ENABLE(VIDEO_PRESENTATION_MODE)
9453 if (m_playbackSessionManager)
9454 m_playbackSessionManager->requestControlledElementID();
9455#endif
9456}
9457
9458void WebPageProxy::handleControlledElementIDResponse(const String& identifier) const
9459{
9460#if PLATFORM(MAC)
9461 pageClient().handleControlledElementIDResponse(identifier);
9462#endif
9463}
9464
9465bool WebPageProxy::isPlayingVideoInEnhancedFullscreen() const
9466{
9467#if ENABLE(VIDEO_PRESENTATION_MODE)
9468 return m_videoFullscreenManager && m_videoFullscreenManager->isPlayingVideoInEnhancedFullscreen();
9469#else
9470 return false;
9471#endif
9472}
9473
9474void WebPageProxy::handleAutoplayEvent(WebCore::AutoplayEvent event, OptionSet<AutoplayEventFlags> flags)
9475{
9476 m_uiClient->handleAutoplayEvent(*this, event, flags);
9477}
9478
9479#if PLATFORM(MAC)
9480void WebPageProxy::performImmediateActionHitTestAtLocation(FloatPoint point)
9481{
9482 send(Messages::WebPage::PerformImmediateActionHitTestAtLocation(point));
9483}
9484
9485void WebPageProxy::immediateActionDidUpdate()
9486{
9487 send(Messages::WebPage::ImmediateActionDidUpdate());
9488}
9489
9490void WebPageProxy::immediateActionDidCancel()
9491{
9492 send(Messages::WebPage::ImmediateActionDidCancel());
9493}
9494
9495void WebPageProxy::immediateActionDidComplete()
9496{
9497 send(Messages::WebPage::ImmediateActionDidComplete());
9498}
9499
9500void WebPageProxy::didPerformImmediateActionHitTest(const WebHitTestResultData& result, bool contentPreventsDefault, const UserData& userData)
9501{
9502 pageClient().didPerformImmediateActionHitTest(result, contentPreventsDefault, m_process->transformHandlesToObjects(userData.object()).get());
9503}
9504
9505NSObject *WebPageProxy::immediateActionAnimationControllerForHitTestResult(RefPtr<API::HitTestResult> hitTestResult, uint64_t type, RefPtr<API::Object> userData)
9506{
9507 return pageClient().immediateActionAnimationControllerForHitTestResult(hitTestResult, type, userData);
9508}
9509
9510void WebPageProxy::handleAcceptedCandidate(WebCore::TextCheckingResult acceptedCandidate)
9511{
9512 send(Messages::WebPage::HandleAcceptedCandidate(acceptedCandidate));
9513}
9514
9515void WebPageProxy::didHandleAcceptedCandidate()
9516{
9517 pageClient().didHandleAcceptedCandidate();
9518}
9519
9520void WebPageProxy::setUseSystemAppearance(bool useSystemAppearance)
9521{
9522 if (useSystemAppearance == m_useSystemAppearance)
9523 return;
9524
9525 m_useSystemAppearance = useSystemAppearance;
9526
9527 if (!hasRunningProcess())
9528 return;
9529
9530 send(Messages::WebPage::SetUseSystemAppearance(useSystemAppearance));
9531}
9532
9533void WebPageProxy::setHeaderBannerHeightForTesting(int height)
9534{
9535 send(Messages::WebPage::SetHeaderBannerHeightForTesting(height));
9536}
9537
9538void WebPageProxy::setFooterBannerHeightForTesting(int height)
9539{
9540 send(Messages::WebPage::SetFooterBannerHeightForTesting(height));
9541}
9542
9543void WebPageProxy::didEndMagnificationGesture()
9544{
9545 send(Messages::WebPage::DidEndMagnificationGesture());
9546}
9547
9548#endif
9549
9550void WebPageProxy::installActivityStateChangeCompletionHandler(CompletionHandler<void()>&& completionHandler)
9551{
9552 if (!hasRunningProcess()) {
9553 completionHandler();
9554 return;
9555 }
9556
9557 m_nextActivityStateChangeCallbacks.append(WTFMove(completionHandler));
9558}
9559
9560void WebPageProxy::imageOrMediaDocumentSizeChanged(const WebCore::IntSize& newSize)
9561{
9562 m_uiClient->imageOrMediaDocumentSizeChanged(newSize);
9563}
9564
9565void WebPageProxy::setShouldDispatchFakeMouseMoveEvents(bool shouldDispatchFakeMouseMoveEvents)
9566{
9567 send(Messages::WebPage::SetShouldDispatchFakeMouseMoveEvents(shouldDispatchFakeMouseMoveEvents));
9568}
9569
9570void WebPageProxy::handleAutoFillButtonClick(const UserData& userData)
9571{
9572 m_uiClient->didClickAutoFillButton(*this, m_process->transformHandlesToObjects(userData.object()).get());
9573}
9574
9575void WebPageProxy::didResignInputElementStrongPasswordAppearance(const UserData& userData)
9576{
9577 m_uiClient->didResignInputElementStrongPasswordAppearance(*this, m_process->transformHandlesToObjects(userData.object()).get());
9578}
9579
9580#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
9581void WebPageProxy::addPlaybackTargetPickerClient(PlaybackTargetClientContextIdentifier contextId)
9582{
9583 pageClient().mediaSessionManager().addPlaybackTargetPickerClient(*this, contextId);
9584}
9585
9586void WebPageProxy::removePlaybackTargetPickerClient(PlaybackTargetClientContextIdentifier contextId)
9587{
9588 pageClient().mediaSessionManager().removePlaybackTargetPickerClient(*this, contextId);
9589}
9590
9591void WebPageProxy::showPlaybackTargetPicker(PlaybackTargetClientContextIdentifier contextId, const WebCore::FloatRect& rect, bool hasVideo)
9592{
9593 pageClient().mediaSessionManager().showPlaybackTargetPicker(*this, contextId, pageClient().rootViewToScreen(IntRect(rect)), hasVideo, useDarkAppearance());
9594}
9595
9596void WebPageProxy::playbackTargetPickerClientStateDidChange(PlaybackTargetClientContextIdentifier contextId, WebCore::MediaProducer::MediaStateFlags state)
9597{
9598 pageClient().mediaSessionManager().clientStateDidChange(*this, contextId, state);
9599}
9600
9601void WebPageProxy::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
9602{
9603 pageClient().mediaSessionManager().setMockMediaPlaybackTargetPickerEnabled(enabled);
9604}
9605
9606void WebPageProxy::setMockMediaPlaybackTargetPickerState(const String& name, WebCore::MediaPlaybackTargetContext::MockState state)
9607{
9608 pageClient().mediaSessionManager().setMockMediaPlaybackTargetPickerState(name, state);
9609}
9610
9611void WebPageProxy::mockMediaPlaybackTargetPickerDismissPopup()
9612{
9613 pageClient().mediaSessionManager().mockMediaPlaybackTargetPickerDismissPopup();
9614}
9615
9616void WebPageProxy::setPlaybackTarget(PlaybackTargetClientContextIdentifier contextId, Ref<MediaPlaybackTarget>&& target)
9617{
9618 if (!hasRunningProcess())
9619 return;
9620
9621 auto context = target->targetContext();
9622 ASSERT(context.type() != MediaPlaybackTargetContext::Type::SerializedAVOutputContext);
9623 if (preferences().useGPUProcessForMediaEnabled())
9624 context.serializeOutputContext();
9625
9626 send(Messages::WebPage::PlaybackTargetSelected(contextId, context));
9627}
9628
9629void WebPageProxy::externalOutputDeviceAvailableDidChange(PlaybackTargetClientContextIdentifier contextId, bool available)
9630{
9631 if (!hasRunningProcess())
9632 return;
9633
9634 send(Messages::WebPage::PlaybackTargetAvailabilityDidChange(contextId, available));
9635}
9636
9637void WebPageProxy::setShouldPlayToPlaybackTarget(PlaybackTargetClientContextIdentifier contextId, bool shouldPlay)
9638{
9639 if (!hasRunningProcess())
9640 return;
9641
9642 send(Messages::WebPage::SetShouldPlayToPlaybackTarget(contextId, shouldPlay));
9643}
9644
9645void WebPageProxy::playbackTargetPickerWasDismissed(PlaybackTargetClientContextIdentifier contextId)
9646{
9647 if (!hasRunningProcess())
9648 return;
9649
9650 send(Messages::WebPage::PlaybackTargetPickerWasDismissed(contextId));
9651}
9652#endif
9653
9654void WebPageProxy::didExceedInactiveMemoryLimitWhileActive()
9655{
9656 WEBPAGEPROXY_RELEASE_LOG_ERROR(PerformanceLogging, "didExceedInactiveMemoryLimitWhileActive");
9657 m_uiClient->didExceedBackgroundResourceLimitWhileInForeground(*this, kWKResourceLimitMemory);
9658}
9659
9660void WebPageProxy::didExceedBackgroundCPULimitWhileInForeground()
9661{
9662 WEBPAGEPROXY_RELEASE_LOG_ERROR(PerformanceLogging, "didExceedBackgroundCPULimitWhileInForeground");
9663 m_uiClient->didExceedBackgroundResourceLimitWhileInForeground(*this, kWKResourceLimitCPU);
9664}
9665
9666void WebPageProxy::didChangeBackgroundColor()
9667{
9668 pageClient().didChangeBackgroundColor();
9669}
9670
9671void WebPageProxy::clearWheelEventTestMonitor()
9672{
9673 if (!hasRunningProcess())
9674 return;
9675
9676 send(Messages::WebPage::ClearWheelEventTestMonitor());
9677}
9678
9679void WebPageProxy::callAfterNextPresentationUpdate(WTF::Function<void (CallbackBase::Error)>&& callback)
9680{
9681 if (!hasRunningProcess() || !m_drawingArea) {
9682 callback(CallbackBase::Error::OwnerWasInvalidated);
9683 return;
9684 }
9685
9686 m_drawingArea->dispatchAfterEnsuringDrawing(WTFMove(callback));
9687}
9688
9689void WebPageProxy::setShouldScaleViewToFitDocument(bool shouldScaleViewToFitDocument)
9690{
9691 if (m_shouldScaleViewToFitDocument == shouldScaleViewToFitDocument)
9692 return;
9693
9694 m_shouldScaleViewToFitDocument = shouldScaleViewToFitDocument;
9695
9696 if (!hasRunningProcess())
9697 return;
9698
9699 send(Messages::WebPage::SetShouldScaleViewToFitDocument(shouldScaleViewToFitDocument));
9700}
9701
9702void WebPageProxy::didRestoreScrollPosition()
9703{
9704 pageClient().didRestoreScrollPosition();
9705}
9706
9707void WebPageProxy::getLoadDecisionForIcon(const WebCore::LinkIcon& icon, CallbackID loadIdentifier)
9708{
9709 m_iconLoadingClient->getLoadDecisionForIcon(icon, [this, protectedThis = makeRef(*this), loadIdentifier] (CompletionHandler<void(API::Data*)>&& callback) {
9710 if (!hasRunningProcess()) {
9711 if (callback)
9712 callback(nullptr);
9713 return;
9714 }
9715
9716 if (!callback) {
9717 sendWithAsyncReply(Messages::WebPage::DidGetLoadDecisionForIcon(false, loadIdentifier), [](auto) { });
9718 return;
9719 }
9720 sendWithAsyncReply(Messages::WebPage::DidGetLoadDecisionForIcon(true, loadIdentifier), [callback = WTFMove(callback)](const IPC::DataReference& iconData) mutable {
9721 callback(API::Data::create(iconData).get());
9722 });
9723 });
9724}
9725
9726WebCore::UserInterfaceLayoutDirection WebPageProxy::userInterfaceLayoutDirection()
9727{
9728 return pageClient().userInterfaceLayoutDirection();
9729}
9730
9731void WebPageProxy::setUserInterfaceLayoutDirection(WebCore::UserInterfaceLayoutDirection userInterfaceLayoutDirection)
9732{
9733 if (!hasRunningProcess())
9734 return;
9735
9736 send(Messages::WebPage::SetUserInterfaceLayoutDirection(static_cast<uint32_t>(userInterfaceLayoutDirection)));
9737}
9738
9739void WebPageProxy::hideValidationMessage()
9740{
9741#if PLATFORM(COCOA)
9742 m_validationBubble = nullptr;
9743#endif
9744}
9745
9746// FIXME: Consolidate with dismissContentRelativeChildWindows
9747void WebPageProxy::closeOverlayedViews()
9748{
9749 hideValidationMessage();
9750
9751#if ENABLE(DATALIST_ELEMENT)
9752 endDataListSuggestions();
9753#endif
9754
9755#if ENABLE(INPUT_TYPE_COLOR)
9756 endColorPicker();
9757#endif
9758
9759#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
9760 endDateTimePicker();
9761#endif
9762}
9763
9764#if ENABLE(POINTER_LOCK)
9765void WebPageProxy::requestPointerLock()
9766{
9767 ASSERT(!m_isPointerLockPending);
9768 ASSERT(!m_isPointerLocked);
9769 m_isPointerLockPending = true;
9770
9771 if (!isViewVisible() || !(m_activityState & ActivityState::IsFocused)) {
9772 didDenyPointerLock();
9773 return;
9774 }
9775 m_uiClient->requestPointerLock(this);
9776}
9777
9778void WebPageProxy::didAllowPointerLock()
9779{
9780 ASSERT(m_isPointerLockPending && !m_isPointerLocked);
9781 m_isPointerLocked = true;
9782 m_isPointerLockPending = false;
9783#if PLATFORM(MAC)
9784 CGDisplayHideCursor(CGMainDisplayID());
9785 CGAssociateMouseAndMouseCursorPosition(false);
9786#endif
9787 send(Messages::WebPage::DidAcquirePointerLock());
9788}
9789
9790void WebPageProxy::didDenyPointerLock()
9791{
9792 ASSERT(m_isPointerLockPending && !m_isPointerLocked);
9793 m_isPointerLockPending = false;
9794 send(Messages::WebPage::DidNotAcquirePointerLock());
9795}
9796
9797void WebPageProxy::requestPointerUnlock()
9798{
9799 if (m_isPointerLocked) {
9800#if PLATFORM(MAC)
9801 CGAssociateMouseAndMouseCursorPosition(true);
9802 CGDisplayShowCursor(CGMainDisplayID());
9803#endif
9804 m_uiClient->didLosePointerLock(this);
9805 send(Messages::WebPage::DidLosePointerLock());
9806 }
9807
9808 if (m_isPointerLockPending) {
9809 m_uiClient->didLosePointerLock(this);
9810 send(Messages::WebPage::DidNotAcquirePointerLock());
9811 }
9812
9813 m_isPointerLocked = false;
9814 m_isPointerLockPending = false;
9815}
9816#endif
9817
9818void WebPageProxy::setURLSchemeHandlerForScheme(Ref<WebURLSchemeHandler>&& handler, const String& scheme)
9819{
9820 auto canonicalizedScheme = WTF::URLParser::maybeCanonicalizeScheme(scheme);
9821 ASSERT(canonicalizedScheme);
9822 ASSERT(!WTF::URLParser::isSpecialScheme(canonicalizedScheme.value()));
9823
9824 auto schemeResult = m_urlSchemeHandlersByScheme.add(canonicalizedScheme.value(), handler.get());
9825 ASSERT_UNUSED(schemeResult, schemeResult.isNewEntry);
9826
9827 auto handlerIdentifier = handler->identifier();
9828 auto handlerIdentifierResult = m_urlSchemeHandlersByIdentifier.add(handlerIdentifier, WTFMove(handler));
9829 ASSERT_UNUSED(handlerIdentifierResult, handlerIdentifierResult.isNewEntry);
9830
9831 send(Messages::WebPage::RegisterURLSchemeHandler(handlerIdentifier, canonicalizedScheme.value()));
9832}
9833
9834WebURLSchemeHandler* WebPageProxy::urlSchemeHandlerForScheme(const String& scheme)
9835{
9836 return scheme.isNull() ? nullptr : m_urlSchemeHandlersByScheme.get(scheme);
9837}
9838
9839void WebPageProxy::startURLSchemeTask(URLSchemeTaskParameters&& parameters)
9840{
9841 startURLSchemeTaskShared(m_process.copyRef(), m_webPageID, WTFMove(parameters));
9842}
9843
9844void WebPageProxy::startURLSchemeTaskShared(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, URLSchemeTaskParameters&& parameters)
9845{
9846 MESSAGE_CHECK(m_process, decltype(m_urlSchemeHandlersByIdentifier)::isValidKey(parameters.handlerIdentifier));
9847 auto iterator = m_urlSchemeHandlersByIdentifier.find(parameters.handlerIdentifier);
9848 MESSAGE_CHECK(process, iterator != m_urlSchemeHandlersByIdentifier.end());
9849
9850 iterator->value->startTask(*this, process, webPageID, WTFMove(parameters), nullptr);
9851}
9852
9853void WebPageProxy::stopURLSchemeTask(uint64_t handlerIdentifier, uint64_t taskIdentifier)
9854{
9855 MESSAGE_CHECK(m_process, decltype(m_urlSchemeHandlersByIdentifier)::isValidKey(handlerIdentifier));
9856 auto iterator = m_urlSchemeHandlersByIdentifier.find(handlerIdentifier);
9857 MESSAGE_CHECK(m_process, iterator != m_urlSchemeHandlersByIdentifier.end());
9858
9859 iterator->value->stopTask(*this, taskIdentifier);
9860}
9861
9862void WebPageProxy::loadSynchronousURLSchemeTask(URLSchemeTaskParameters&& parameters, Messages::WebPageProxy::LoadSynchronousURLSchemeTask::DelayedReply&& reply)
9863{
9864 MESSAGE_CHECK(m_process, decltype(m_urlSchemeHandlersByIdentifier)::isValidKey(parameters.handlerIdentifier));
9865 auto iterator = m_urlSchemeHandlersByIdentifier.find(parameters.handlerIdentifier);
9866 MESSAGE_CHECK(m_process, iterator != m_urlSchemeHandlersByIdentifier.end());
9867
9868 iterator->value->startTask(*this, m_process, m_webPageID, WTFMove(parameters), WTFMove(reply));
9869}
9870
9871#if ENABLE(RESOURCE_LOAD_STATISTICS)
9872void WebPageProxy::requestStorageAccessConfirm(const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, FrameIdentifier frameID, CompletionHandler<void(bool)>&& completionHandler)
9873{
9874 m_uiClient->requestStorageAccessConfirm(*this, m_process->webFrame(frameID), subFrameDomain, topFrameDomain, WTFMove(completionHandler));
9875}
9876
9877void WebPageProxy::didCommitCrossSiteLoadWithDataTransferFromPrevalentResource()
9878{
9879 if (!hasRunningProcess())
9880 return;
9881
9882 send(Messages::WebPage::WasLoadedWithDataTransferFromPrevalentResource());
9883}
9884#endif
9885
9886bool WebPageProxy::useDarkAppearance() const
9887{
9888 return pageClient().effectiveAppearanceIsDark();
9889}
9890
9891bool WebPageProxy::useElevatedUserInterfaceLevel() const
9892{
9893 return pageClient().effectiveUserInterfaceLevelIsElevated();
9894}
9895
9896void WebPageProxy::effectiveAppearanceDidChange()
9897{
9898 if (!hasRunningProcess())
9899 return;
9900
9901 send(Messages::WebPage::EffectiveAppearanceDidChange(useDarkAppearance(), useElevatedUserInterfaceLevel()));
9902}
9903
9904#if HAVE(TOUCH_BAR)
9905void WebPageProxy::touchBarMenuDataChanged(const TouchBarMenuData& touchBarMenuData)
9906{
9907 m_touchBarMenuData = touchBarMenuData;
9908}
9909
9910void WebPageProxy::touchBarMenuItemDataAdded(const TouchBarMenuItemData& touchBarMenuItemData)
9911{
9912 m_touchBarMenuData.addMenuItem(touchBarMenuItemData);
9913}
9914
9915void WebPageProxy::touchBarMenuItemDataRemoved(const TouchBarMenuItemData& touchBarMenuItemData)
9916{
9917 m_touchBarMenuData.removeMenuItem(touchBarMenuItemData);
9918}
9919#endif
9920
9921#if HAVE(PASTEBOARD_DATA_OWNER)
9922
9923DataOwnerType WebPageProxy::dataOwnerForPasteboard(PasteboardAccessIntent intent) const
9924{
9925 return pageClient().dataOwnerForPasteboard(intent);
9926}
9927
9928#endif
9929
9930#if ENABLE(ATTACHMENT_ELEMENT)
9931
9932void WebPageProxy::writePromisedAttachmentToPasteboard(WebCore::PromisedAttachmentInfo&& info)
9933{
9934 pageClient().writePromisedAttachmentToPasteboard(WTFMove(info));
9935}
9936
9937RefPtr<API::Attachment> WebPageProxy::attachmentForIdentifier(const String& identifier) const
9938{
9939 if (identifier.isEmpty())
9940 return nullptr;
9941
9942 return m_attachmentIdentifierToAttachmentMap.get(identifier);
9943}
9944
9945void WebPageProxy::insertAttachment(Ref<API::Attachment>&& attachment, CompletionHandler<void()>&& callback)
9946{
9947 auto attachmentIdentifier = attachment->identifier();
9948 sendWithAsyncReply(Messages::WebPage::InsertAttachment(attachmentIdentifier, attachment->fileSizeForDisplay(), attachment->fileName(), attachment->contentType()), WTFMove(callback));
9949 m_attachmentIdentifierToAttachmentMap.set(attachmentIdentifier, WTFMove(attachment));
9950}
9951
9952void WebPageProxy::updateAttachmentAttributes(const API::Attachment& attachment, CompletionHandler<void()>&& callback)
9953{
9954 IPC::SharedBufferDataReference dataReference;
9955 if (auto data = attachment.enclosingImageData())
9956 dataReference = { *data };
9957
9958 sendWithAsyncReply(Messages::WebPage::UpdateAttachmentAttributes(attachment.identifier(), attachment.fileSizeForDisplay(), attachment.contentType(), attachment.fileName(), WTFMove(dataReference)), WTFMove(callback));
9959}
9960
9961#if HAVE(QUICKLOOK_THUMBNAILING)
9962void WebPageProxy::updateAttachmentIcon(const String& identifier, const RefPtr<ShareableBitmap>& bitmap)
9963{
9964 if (!hasRunningProcess())
9965 return;
9966
9967 ShareableBitmap::Handle handle;
9968 if (bitmap)
9969 bitmap->createHandle(handle);
9970
9971 send(Messages::WebPage::UpdateAttachmentIcon(identifier, handle));
9972}
9973#endif
9974
9975void WebPageProxy::registerAttachmentIdentifierFromData(const String& identifier, const String& contentType, const String& preferredFileName, const IPC::SharedBufferCopy& data)
9976{
9977 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
9978 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
9979
9980 if (attachmentForIdentifier(identifier))
9981 return;
9982
9983 auto attachment = ensureAttachment(identifier);
9984 attachment->setContentType(contentType);
9985 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
9986
9987 platformRegisterAttachment(WTFMove(attachment), preferredFileName, data);
9988}
9989
9990void WebPageProxy::registerAttachmentIdentifierFromFilePath(const String& identifier, const String& contentType, const String& filePath)
9991{
9992 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
9993 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
9994
9995 if (attachmentForIdentifier(identifier))
9996 return;
9997
9998 auto attachment = ensureAttachment(identifier);
9999 attachment->setContentType(contentType);
10000 attachment->setFilePath(filePath);
10001 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
10002 platformRegisterAttachment(WTFMove(attachment), filePath);
10003#if HAVE(QUICKLOOK_THUMBNAILING)
10004 requestThumbnailWithPath(identifier, filePath);
10005#endif
10006}
10007
10008void WebPageProxy::registerAttachmentIdentifier(const String& identifier)
10009{
10010 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10011 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10012
10013 if (!attachmentForIdentifier(identifier))
10014 m_attachmentIdentifierToAttachmentMap.set(identifier, ensureAttachment(identifier));
10015}
10016
10017void WebPageProxy::registerAttachmentsFromSerializedData(Vector<WebCore::SerializedAttachmentData>&& data)
10018{
10019 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10020
10021 for (auto& serializedData : data) {
10022 auto identifier = WTFMove(serializedData.identifier);
10023 if (!attachmentForIdentifier(identifier))
10024 ensureAttachment(identifier)->updateFromSerializedRepresentation(WTFMove(serializedData.data), WTFMove(serializedData.mimeType));
10025 }
10026}
10027
10028void WebPageProxy::cloneAttachmentData(const String& fromIdentifier, const String& toIdentifier)
10029{
10030 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10031 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(fromIdentifier));
10032 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(toIdentifier));
10033
10034 auto newAttachment = ensureAttachment(toIdentifier);
10035 auto existingAttachment = attachmentForIdentifier(fromIdentifier);
10036 if (!existingAttachment) {
10037 ASSERT_NOT_REACHED();
10038 return;
10039 }
10040
10041 newAttachment->setContentType(existingAttachment->contentType());
10042 newAttachment->setFilePath(existingAttachment->filePath());
10043
10044 platformCloneAttachment(existingAttachment.releaseNonNull(), WTFMove(newAttachment));
10045}
10046
10047void WebPageProxy::invalidateAllAttachments()
10048{
10049 for (auto& attachment : m_attachmentIdentifierToAttachmentMap.values()) {
10050 if (attachment->insertionState() == API::Attachment::InsertionState::Inserted)
10051 didRemoveAttachment(attachment.get());
10052 attachment->invalidate();
10053 }
10054 m_attachmentIdentifierToAttachmentMap.clear();
10055}
10056
10057void WebPageProxy::serializedAttachmentDataForIdentifiers(const Vector<String>& identifiers, CompletionHandler<void(Vector<WebCore::SerializedAttachmentData>&&)>&& completionHandler)
10058{
10059 Vector<WebCore::SerializedAttachmentData> serializedData;
10060
10061 MESSAGE_CHECK_COMPLETION(m_process, m_preferences->attachmentElementEnabled(), completionHandler(WTFMove(serializedData)));
10062
10063 for (const auto& identifier : identifiers) {
10064 auto attachment = attachmentForIdentifier(identifier);
10065 if (!attachment)
10066 continue;
10067
10068 auto data = attachment->createSerializedRepresentation();
10069 if (!data)
10070 continue;
10071
10072 serializedData.append({ identifier, attachment->mimeType(), data.releaseNonNull() });
10073 }
10074 completionHandler(WTFMove(serializedData));
10075}
10076
10077void WebPageProxy::didInvalidateDataForAttachment(API::Attachment& attachment)
10078{
10079 pageClient().didInvalidateDataForAttachment(attachment);
10080}
10081
10082WebPageProxy::ShouldUpdateAttachmentAttributes WebPageProxy::willUpdateAttachmentAttributes(const API::Attachment& attachment)
10083{
10084 return ShouldUpdateAttachmentAttributes::Yes;
10085}
10086
10087#if !PLATFORM(COCOA)
10088
10089void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&&, const String&, const IPC::SharedBufferCopy&)
10090{
10091}
10092
10093void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&&, const String&)
10094{
10095}
10096
10097void WebPageProxy::platformCloneAttachment(Ref<API::Attachment>&&, Ref<API::Attachment>&&)
10098{
10099}
10100
10101#endif
10102
10103void WebPageProxy::didInsertAttachmentWithIdentifier(const String& identifier, const String& source, bool hasEnclosingImage)
10104{
10105 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10106 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10107
10108 auto attachment = ensureAttachment(identifier);
10109 attachment->setHasEnclosingImage(hasEnclosingImage);
10110 attachment->setInsertionState(API::Attachment::InsertionState::Inserted);
10111 pageClient().didInsertAttachment(attachment.get(), source);
10112
10113 if (!attachment->isEmpty() && hasEnclosingImage)
10114 updateAttachmentAttributes(attachment.get(), [] { });
10115}
10116
10117void WebPageProxy::didRemoveAttachmentWithIdentifier(const String& identifier)
10118{
10119 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10120 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10121
10122 if (auto attachment = attachmentForIdentifier(identifier))
10123 didRemoveAttachment(*attachment);
10124}
10125
10126void WebPageProxy::didRemoveAttachment(API::Attachment& attachment)
10127{
10128 attachment.setInsertionState(API::Attachment::InsertionState::NotInserted);
10129 pageClient().didRemoveAttachment(attachment);
10130}
10131
10132Ref<API::Attachment> WebPageProxy::ensureAttachment(const String& identifier)
10133{
10134 if (auto existingAttachment = attachmentForIdentifier(identifier))
10135 return *existingAttachment;
10136
10137 auto attachment = API::Attachment::create(identifier, *this);
10138 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
10139 return attachment;
10140}
10141
10142#endif // ENABLE(ATTACHMENT_ELEMENT)
10143
10144#if ENABLE(APPLICATION_MANIFEST)
10145void WebPageProxy::getApplicationManifest(CompletionHandler<void(const std::optional<WebCore::ApplicationManifest>&)>&& callback)
10146{
10147 sendWithAsyncReply(Messages::WebPage::GetApplicationManifest(), WTFMove(callback));
10148}
10149#endif
10150
10151#if ENABLE(APP_HIGHLIGHTS)
10152void WebPageProxy::storeAppHighlight(const WebCore::AppHighlight& highlight)
10153{
10154 MESSAGE_CHECK(m_process, !highlight.highlight->isEmpty());
10155
10156 pageClient().storeAppHighlight(highlight);
10157
10158}
10159#endif
10160
10161namespace {
10162enum class CompletionCondition {
10163 Cancellation,
10164 Error,
10165 Success,
10166 Timeout,
10167};
10168struct MessageType {
10169 CompletionCondition condition;
10170 Seconds seconds;
10171 String message;
10172};
10173}
10174
10175void WebPageProxy::reportPageLoadResult(const ResourceError& error)
10176{
10177 static const NeverDestroyed<Vector<MessageType>> messages(std::initializer_list<MessageType> {
10178 { CompletionCondition::Cancellation, 2_s, DiagnosticLoggingKeys::canceledLessThan2SecondsKey() },
10179 { CompletionCondition::Cancellation, 5_s, DiagnosticLoggingKeys::canceledLessThan5SecondsKey() },
10180 { CompletionCondition::Cancellation, 20_s, DiagnosticLoggingKeys::canceledLessThan20SecondsKey() },
10181 { CompletionCondition::Cancellation, Seconds::infinity(), DiagnosticLoggingKeys::canceledMoreThan20SecondsKey() },
10182
10183 { CompletionCondition::Error, 2_s, DiagnosticLoggingKeys::failedLessThan2SecondsKey() },
10184 { CompletionCondition::Error, 5_s, DiagnosticLoggingKeys::failedLessThan5SecondsKey() },
10185 { CompletionCondition::Error, 20_s, DiagnosticLoggingKeys::failedLessThan20SecondsKey() },
10186 { CompletionCondition::Error, Seconds::infinity(), DiagnosticLoggingKeys::failedMoreThan20SecondsKey() },
10187
10188 { CompletionCondition::Success, 2_s, DiagnosticLoggingKeys::succeededLessThan2SecondsKey() },
10189 { CompletionCondition::Success, 5_s, DiagnosticLoggingKeys::succeededLessThan5SecondsKey() },
10190 { CompletionCondition::Success, 20_s, DiagnosticLoggingKeys::succeededLessThan20SecondsKey() },
10191 { CompletionCondition::Success, Seconds::infinity(), DiagnosticLoggingKeys::succeededMoreThan20SecondsKey() },
10192
10193 { CompletionCondition::Timeout, Seconds::infinity(), DiagnosticLoggingKeys::timedOutKey() }
10194 });
10195
10196 if (!m_pageLoadStart)
10197 return;
10198
10199 auto pageLoadTime = MonotonicTime::now() - *m_pageLoadStart;
10200 m_pageLoadStart = std::nullopt;
10201
10202 CompletionCondition condition { CompletionCondition::Success };
10203 if (error.isCancellation())
10204 condition = CompletionCondition::Cancellation;
10205 else if (error.isTimeout())
10206 condition = CompletionCondition::Timeout;
10207 else if (!error.isNull() || error.errorCode())
10208 condition = CompletionCondition::Error;
10209
10210 for (auto& messageItem : messages.get()) {
10211 if (condition == messageItem.condition && pageLoadTime < messageItem.seconds) {
10212 logDiagnosticMessage(DiagnosticLoggingKeys::telemetryPageLoadKey(), messageItem.message, ShouldSample::No);
10213 logDiagnosticMessage(DiagnosticLoggingKeys::telemetryPageLoadKey(), DiagnosticLoggingKeys::occurredKey(), ShouldSample::No);
10214 break;
10215 }
10216 }
10217}
10218
10219void WebPageProxy::setDefersLoadingForTesting(bool defersLoading)
10220{
10221 send(Messages::WebPage::SetDefersLoading(defersLoading));
10222}
10223
10224void WebPageProxy::getIsViewVisible(bool& result)
10225{
10226 result = isViewVisible();
10227}
10228
10229void WebPageProxy::updateCurrentModifierState()
10230{
10231#if PLATFORM(COCOA)
10232 auto modifiers = PlatformKeyboardEvent::currentStateOfModifierKeys();
10233 send(Messages::WebPage::UpdateCurrentModifierState(modifiers));
10234#endif
10235}
10236
10237bool WebPageProxy::checkURLReceivedFromCurrentOrPreviousWebProcess(WebProcessProxy& process, const String& urlString)
10238{
10239 return checkURLReceivedFromCurrentOrPreviousWebProcess(process, URL(URL(), urlString));
10240}
10241
10242bool WebPageProxy::checkURLReceivedFromCurrentOrPreviousWebProcess(WebProcessProxy& process, const URL& url)
10243{
10244 if (!url.isLocalFile())
10245 return true;
10246
10247 if (m_mayHaveUniversalFileReadSandboxExtension)
10248 return true;
10249
10250 String path = url.fileSystemPath();
10251 auto startsWithURLPath = [&path](const String& visitedPath) {
10252 return path.startsWith(visitedPath);
10253 };
10254
10255 auto localPathsEnd = m_previouslyVisitedPaths.end();
10256 if (std::find_if(m_previouslyVisitedPaths.begin(), localPathsEnd, startsWithURLPath) != localPathsEnd)
10257 return true;
10258
10259 return process.checkURLReceivedFromWebProcess(url);
10260}
10261
10262void WebPageProxy::addPreviouslyVisitedPath(const String& path)
10263{
10264 m_previouslyVisitedPaths.add(path);
10265}
10266
10267void WebPageProxy::willAcquireUniversalFileReadSandboxExtension(WebProcessProxy& process)
10268{
10269 m_mayHaveUniversalFileReadSandboxExtension = true;
10270 process.willAcquireUniversalFileReadSandboxExtension();
10271}
10272
10273void WebPageProxy::simulateDeviceOrientationChange(double alpha, double beta, double gamma)
10274{
10275 send(Messages::WebPage::SimulateDeviceOrientationChange(alpha, beta, gamma));
10276}
10277
10278#if ENABLE(DATA_DETECTION)
10279
10280void WebPageProxy::detectDataInAllFrames(WebCore::DataDetectorType types, CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
10281{
10282 if (!hasRunningProcess()) {
10283 completionHandler({ });
10284 return;
10285 }
10286 sendWithAsyncReply(Messages::WebPage::DetectDataInAllFrames(static_cast<uint64_t>(types)), WTFMove(completionHandler));
10287}
10288
10289void WebPageProxy::removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
10290{
10291 if (!hasRunningProcess()) {
10292 completionHandler({ });
10293 return;
10294 }
10295 sendWithAsyncReply(Messages::WebPage::RemoveDataDetectedLinks(), WTFMove(completionHandler));
10296}
10297
10298#endif
10299
10300#if USE(SYSTEM_PREVIEW)
10301void WebPageProxy::systemPreviewActionTriggered(const WebCore::SystemPreviewInfo& previewInfo, const String& message)
10302{
10303 send(Messages::WebPage::SystemPreviewActionTriggered(previewInfo, message));
10304}
10305#endif
10306
10307void WebPageProxy::dumpPrivateClickMeasurement(CompletionHandler<void(const String&)>&& completionHandler)
10308{
10309 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::DumpPrivateClickMeasurement(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10310}
10311
10312void WebPageProxy::clearPrivateClickMeasurement(CompletionHandler<void()>&& completionHandler)
10313{
10314 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::ClearPrivateClickMeasurement(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10315}
10316
10317void WebPageProxy::setPrivateClickMeasurementOverrideTimerForTesting(bool value, CompletionHandler<void()>&& completionHandler)
10318{
10319 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementOverrideTimerForTesting(m_websiteDataStore->sessionID(), value), WTFMove(completionHandler));
10320}
10321
10322void WebPageProxy::markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler)
10323{
10324 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::MarkAttributedPrivateClickMeasurementsAsExpiredForTesting(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10325}
10326
10327void WebPageProxy::simulateResourceLoadStatisticsSessionRestart(CompletionHandler<void()>&& completionHandler)
10328{
10329 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SimulateResourceLoadStatisticsSessionRestart(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10330}
10331
10332void WebPageProxy::setPrivateClickMeasurementTokenPublicKeyURLForTesting(const URL& url, CompletionHandler<void()>&& completionHandler)
10333{
10334 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementTokenPublicKeyURLForTesting(m_websiteDataStore->sessionID(), url), WTFMove(completionHandler));
10335}
10336
10337void WebPageProxy::setPrivateClickMeasurementTokenSignatureURLForTesting(const URL& url, CompletionHandler<void()>&& completionHandler)
10338{
10339 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementTokenSignatureURLForTesting(m_websiteDataStore->sessionID(), url), WTFMove(completionHandler));
10340}
10341
10342void WebPageProxy::setPrivateClickMeasurementAttributionReportURLsForTesting(const URL& sourceURL, const URL& destinationURL, CompletionHandler<void()>&& completionHandler)
10343{
10344 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementAttributionReportURLsForTesting(m_websiteDataStore->sessionID(), sourceURL, destinationURL), WTFMove(completionHandler));
10345}
10346
10347void WebPageProxy::markPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler)
10348{
10349 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::MarkPrivateClickMeasurementsAsExpiredForTesting(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10350}
10351
10352void WebPageProxy::setPCMFraudPreventionValuesForTesting(const String& unlinkableToken, const String& secretToken, const String& signature, const String& keyID, CompletionHandler<void()>&& completionHandler)
10353{
10354 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPCMFraudPreventionValuesForTesting(m_websiteDataStore->sessionID(), unlinkableToken, secretToken, signature, keyID), WTFMove(completionHandler));
10355}
10356
10357#if ENABLE(SPEECH_SYNTHESIS)
10358
10359void WebPageProxy::resetSpeechSynthesizer()
10360{
10361 if (!m_speechSynthesisData)
10362 return;
10363
10364 auto& synthesisData = speechSynthesisData();
10365 synthesisData.speakingFinishedCompletionHandler = nullptr;
10366 synthesisData.speakingStartedCompletionHandler = nullptr;
10367 synthesisData.speakingPausedCompletionHandler = nullptr;
10368 synthesisData.speakingResumedCompletionHandler = nullptr;
10369 if (synthesisData.synthesizer)
10370 synthesisData.synthesizer->resetState();
10371}
10372
10373WebPageProxy::SpeechSynthesisData& WebPageProxy::speechSynthesisData()
10374{
10375 if (!m_speechSynthesisData)
10376 m_speechSynthesisData = SpeechSynthesisData { makeUnique<PlatformSpeechSynthesizer>(this), nullptr, nullptr, nullptr, nullptr, nullptr };
10377 return *m_speechSynthesisData;
10378}
10379
10380void WebPageProxy::speechSynthesisVoiceList(CompletionHandler<void(Vector<WebSpeechSynthesisVoice>&&)>&& completionHandler)
10381{
10382 auto& voiceList = speechSynthesisData().synthesizer->voiceList();
10383 Vector<WebSpeechSynthesisVoice> result;
10384 result.reserveInitialCapacity(voiceList.size());
10385 for (auto& voice : voiceList)
10386 result.uncheckedAppend(WebSpeechSynthesisVoice { voice->voiceURI(), voice->name(), voice->lang(), voice->localService(), voice->isDefault() });
10387 completionHandler(WTFMove(result));
10388}
10389
10390void WebPageProxy::speechSynthesisSetFinishedCallback(CompletionHandler<void()>&& completionHandler)
10391{
10392 speechSynthesisData().speakingFinishedCompletionHandler = WTFMove(completionHandler);
10393}
10394
10395void WebPageProxy::speechSynthesisSpeak(const String& text, const String& lang, float volume, float rate, float pitch, MonotonicTime startTime, const String& voiceURI, const String& voiceName, const String& voiceLang, bool localService, bool defaultVoice, CompletionHandler<void()>&& completionHandler)
10396{
10397 auto voice = WebCore::PlatformSpeechSynthesisVoice::create(voiceURI, voiceName, voiceLang, localService, defaultVoice);
10398 auto utterance = WebCore::PlatformSpeechSynthesisUtterance::create(*this);
10399 utterance->setText(text);
10400 utterance->setLang(lang);
10401 utterance->setVolume(volume);
10402 utterance->setRate(rate);
10403 utterance->setPitch(pitch);
10404 utterance->setVoice(&voice.get());
10405
10406 speechSynthesisData().speakingStartedCompletionHandler = WTFMove(completionHandler);
10407 speechSynthesisData().utterance = WTFMove(utterance);
10408 speechSynthesisData().synthesizer->speak(m_speechSynthesisData->utterance.get());
10409}
10410
10411void WebPageProxy::speechSynthesisCancel()
10412{
10413 speechSynthesisData().synthesizer->cancel();
10414}
10415
10416void WebPageProxy::speechSynthesisPause(CompletionHandler<void()>&& completionHandler)
10417{
10418 speechSynthesisData().speakingPausedCompletionHandler = WTFMove(completionHandler);
10419 speechSynthesisData().synthesizer->pause();
10420}
10421
10422void WebPageProxy::speechSynthesisResume(CompletionHandler<void()>&& completionHandler)
10423{
10424 speechSynthesisData().speakingResumedCompletionHandler = WTFMove(completionHandler);
10425 speechSynthesisData().synthesizer->resume();
10426}
10427#endif // ENABLE(SPEECH_SYNTHESIS)
10428
10429#if !PLATFORM(IOS_FAMILY)
10430
10431WebContentMode WebPageProxy::effectiveContentModeAfterAdjustingPolicies(API::WebsitePolicies&, const WebCore::ResourceRequest&)
10432{
10433 return WebContentMode::Recommended;
10434}
10435
10436#endif // !PLATFORM(IOS_FAMILY)
10437
10438void WebPageProxy::addObserver(WebViewDidMoveToWindowObserver& observer)
10439{
10440 auto result = m_webViewDidMoveToWindowObservers.add(&observer, makeWeakPtr(observer));
10441 ASSERT_UNUSED(result, result.isNewEntry);
10442}
10443
10444void WebPageProxy::removeObserver(WebViewDidMoveToWindowObserver& observer)
10445{
10446 auto result = m_webViewDidMoveToWindowObservers.remove(&observer);
10447 ASSERT_UNUSED(result, result);
10448}
10449
10450void WebPageProxy::webViewDidMoveToWindow()
10451{
10452 auto observersCopy = m_webViewDidMoveToWindowObservers;
10453 for (const auto& observer : observersCopy) {
10454 if (!observer.value)
10455 continue;
10456 observer.value->webViewDidMoveToWindow();
10457 }
10458}
10459
10460void WebPageProxy::setCanShowPlaceholder(const WebCore::ElementContext& context, bool canShowPlaceholder)
10461{
10462 if (hasRunningProcess())
10463 send(Messages::WebPage::SetCanShowPlaceholder(context, canShowPlaceholder));
10464}
10465
10466Logger& WebPageProxy::logger()
10467{
10468 if (!m_logger) {
10469 m_logger = Logger::create(this);
10470 // FIXME: Does this really need to be disabled in ephemeral sessions?
10471 m_logger->setEnabled(this, !sessionID().isEphemeral());
10472 }
10473
10474 return *m_logger;
10475}
10476
10477void WebPageProxy::configureLoggingChannel(const String& channelName, WTFLogChannelState state, WTFLogLevel level)
10478{
10479#if !RELEASE_LOG_DISABLED
10480 auto* channel = getLogChannel(channelName);
10481 if (!channel)
10482 return;
10483
10484 channel->state = state;
10485 channel->level = level;
10486#else
10487 UNUSED_PARAM(channelName);
10488 UNUSED_PARAM(state);
10489 UNUSED_PARAM(level);
10490#endif
10491}
10492
10493#if HAVE(APP_SSO)
10494void WebPageProxy::decidePolicyForSOAuthorizationLoad(const String& extension, CompletionHandler<void(SOAuthorizationLoadPolicy)>&& completionHandler)
10495{
10496 m_navigationClient->decidePolicyForSOAuthorizationLoad(*this, SOAuthorizationLoadPolicy::Allow, extension, WTFMove(completionHandler));
10497}
10498#endif
10499
10500#if ENABLE(WEB_AUTHN)
10501void WebPageProxy::setMockWebAuthenticationConfiguration(MockWebAuthenticationConfiguration&& configuration)
10502{
10503 m_websiteDataStore->setMockWebAuthenticationConfiguration(WTFMove(configuration));
10504}
10505#endif
10506
10507void WebPageProxy::startTextManipulations(const Vector<WebCore::TextManipulationController::ExclusionRule>& exclusionRules,
10508 TextManipulationItemCallback&& callback, WTF::CompletionHandler<void()>&& completionHandler)
10509{
10510 if (!hasRunningProcess()) {
10511 completionHandler();
10512 return;
10513 }
10514 m_textManipulationItemCallback = WTFMove(callback);
10515 sendWithAsyncReply(Messages::WebPage::StartTextManipulations(exclusionRules), WTFMove(completionHandler));
10516}
10517
10518void WebPageProxy::didFindTextManipulationItems(const Vector<WebCore::TextManipulationController::ManipulationItem>& items)
10519{
10520 if (!m_textManipulationItemCallback)
10521 return;
10522 m_textManipulationItemCallback(items);
10523}
10524
10525void WebPageProxy::completeTextManipulation(const Vector<WebCore::TextManipulationController::ManipulationItem>& items,
10526 WTF::Function<void(bool allFailed, const Vector<WebCore::TextManipulationController::ManipulationFailure>&)>&& completionHandler)
10527{
10528 if (!hasRunningProcess()) {
10529 completionHandler(true, { });
10530 return;
10531 }
10532 sendWithAsyncReply(Messages::WebPage::CompleteTextManipulation(items), WTFMove(completionHandler));
10533}
10534
10535void WebPageProxy::setCORSDisablingPatterns(Vector<String>&& patterns)
10536{
10537 m_corsDisablingPatterns = WTFMove(patterns);
10538 send(Messages::WebPage::UpdateCORSDisablingPatterns(m_corsDisablingPatterns));
10539}
10540
10541void WebPageProxy::setOverriddenMediaType(const String& mediaType)
10542{
10543 m_overriddenMediaType = mediaType;
10544 send(Messages::WebPage::SetOverriddenMediaType(mediaType));
10545}
10546
10547void WebPageProxy::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension)
10548{
10549 send(Messages::WebPage::SetIsTakingSnapshotsForApplicationSuspension(isTakingSnapshotsForApplicationSuspension));
10550}
10551
10552void WebPageProxy::setNeedsDOMWindowResizeEvent()
10553{
10554 send(Messages::WebPage::SetNeedsDOMWindowResizeEvent());
10555}
10556
10557#if !PLATFORM(IOS_FAMILY)
10558bool WebPageProxy::shouldForceForegroundPriorityForClientNavigation() const
10559{
10560 return false;
10561}
10562#endif
10563
10564void WebPageProxy::getProcessDisplayName(CompletionHandler<void(String&&)>&& completionHandler)
10565{
10566 sendWithAsyncReply(Messages::WebPage::GetProcessDisplayName(), WTFMove(completionHandler));
10567}
10568
10569void WebPageProxy::setOrientationForMediaCapture(uint64_t orientation)
10570{
10571#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
10572 if (auto* proxy = m_process->userMediaCaptureManagerProxy())
10573 proxy->setOrientation(orientation);
10574
10575 auto* gpuProcess = m_process->processPool().gpuProcess();
10576 if (gpuProcess && preferences().captureVideoInGPUProcessEnabled())
10577 gpuProcess->setOrientationForMediaCapture(orientation);
10578#endif
10579}
10580
10581#if ENABLE(RESOURCE_LOAD_STATISTICS)
10582void WebPageProxy::getLoadedSubresourceDomains(CompletionHandler<void(Vector<RegistrableDomain>&&)>&& completionHandler)
10583{
10584 sendWithAsyncReply(Messages::WebPage::GetLoadedSubresourceDomains(), WTFMove(completionHandler));
10585}
10586
10587void WebPageProxy::clearLoadedSubresourceDomains()
10588{
10589 send(Messages::WebPage::ClearLoadedSubresourceDomains());
10590}
10591#endif
10592
10593#if ENABLE(GPU_PROCESS)
10594void WebPageProxy::gpuProcessExited(GPUProcessTerminationReason)
10595{
10596#if HAVE(VISIBILITY_PROPAGATION_VIEW)
10597 m_contextIDForVisibilityPropagationInGPUProcess = 0;
10598#endif
10599
10600 pageClient().gpuProcessDidExit();
10601
10602#if ENABLE(MEDIA_STREAM)
10603 bool shouldAllowAudioCapture = isCapturingAudio() && preferences().captureAudioInGPUProcessEnabled();
10604 bool shouldAllowVideoCapture = isCapturingVideo() && preferences().captureVideoInGPUProcessEnabled();
10605 bool shouldAllowDisplayCapture = false;
10606 if (shouldAllowAudioCapture || shouldAllowVideoCapture) {
10607 auto& gpuProcess = process().processPool().ensureGPUProcess();
10608 gpuProcess.updateCaptureAccess(shouldAllowAudioCapture, shouldAllowVideoCapture, shouldAllowDisplayCapture, m_process->coreProcessIdentifier(), [] { });
10609 }
10610#endif
10611}
10612#endif
10613
10614#if ENABLE(CONTEXT_MENUS) && !PLATFORM(MAC)
10615
10616void WebPageProxy::platformDidSelectItemFromActiveContextMenu(const WebContextMenuItemData&)
10617{
10618}
10619
10620#endif
10621
10622#if !PLATFORM(COCOA)
10623
10624void WebPageProxy::willPerformPasteCommand()
10625{
10626}
10627
10628#endif
10629
10630void WebPageProxy::dispatchActivityStateUpdateForTesting()
10631{
10632 RunLoop::current().dispatch([protectedThis = makeRef(*this)] {
10633 protectedThis->dispatchActivityStateChange();
10634 });
10635}
10636
10637void WebPageProxy::requestSpeechRecognitionPermission(WebCore::SpeechRecognitionRequest& request, CompletionHandler<void(std::optional<SpeechRecognitionError>&&)>&& completionHandler)
10638{
10639 if (!m_speechRecognitionPermissionManager)
10640 m_speechRecognitionPermissionManager = makeUnique<SpeechRecognitionPermissionManager>(*this);
10641
10642 m_speechRecognitionPermissionManager->request(request, WTFMove(completionHandler));
10643}
10644
10645void WebPageProxy::requestSpeechRecognitionPermissionByDefaultAction(const WebCore::SecurityOriginData& origin, CompletionHandler<void(bool)>&& completionHandler)
10646{
10647 if (!m_speechRecognitionPermissionManager) {
10648 completionHandler(false);
10649 return;
10650 }
10651
10652 m_speechRecognitionPermissionManager->decideByDefaultAction(origin, WTFMove(completionHandler));
10653}
10654
10655void WebPageProxy::requestUserMediaPermissionForSpeechRecognition(FrameIdentifier frameIdentifier, const WebCore::SecurityOrigin& requestingOrigin, const WebCore::SecurityOrigin& topOrigin, CompletionHandler<void(bool)>&& completionHandler)
10656{
10657#if ENABLE(MEDIA_STREAM)
10658 auto captureDevice = SpeechRecognitionCaptureSource::findCaptureDevice();
10659 if (!captureDevice)
10660 completionHandler(false);
10661
10662 userMediaPermissionRequestManager().checkUserMediaPermissionForSpeechRecognition(frameIdentifier, requestingOrigin, topOrigin, *captureDevice, WTFMove(completionHandler));
10663#else
10664 completionHandler(false);
10665#endif
10666}
10667
10668void WebPageProxy::requestMediaKeySystemPermissionByDefaultAction(const WebCore::SecurityOriginData& origin, CompletionHandler<void(bool)>&& completionHandler)
10669{
10670 completionHandler(true);
10671}
10672
10673#if ENABLE(MEDIA_STREAM)
10674
10675WebCore::CaptureSourceOrError WebPageProxy::createRealtimeMediaSourceForSpeechRecognition()
10676{
10677 auto captureDevice = SpeechRecognitionCaptureSource::findCaptureDevice();
10678 if (!captureDevice)
10679 return CaptureSourceOrError { "No device is available for capture" };
10680
10681 if (preferences().captureAudioInGPUProcessEnabled())
10682 return CaptureSourceOrError { SpeechRecognitionRemoteRealtimeMediaSource::create(m_process->ensureSpeechRecognitionRemoteRealtimeMediaSourceManager(), *captureDevice) };
10683
10684#if PLATFORM(IOS_FAMILY)
10685 return CaptureSourceOrError { SpeechRecognitionRemoteRealtimeMediaSource::create(m_process->ensureSpeechRecognitionRemoteRealtimeMediaSourceManager(), *captureDevice) };
10686#else
10687 return SpeechRecognitionCaptureSource::createRealtimeMediaSource(*captureDevice);
10688#endif
10689}
10690
10691#endif
10692
10693#if HAVE(ARKIT_INLINE_PREVIEW_IOS)
10694void WebPageProxy::takeModelElementFullscreen(WebCore::GraphicsLayer::PlatformLayerID contentLayerId)
10695{
10696 modelElementController()->takeModelElementFullscreen(contentLayerId);
10697}
10698#endif
10699
10700#if HAVE(ARKIT_INLINE_PREVIEW_MAC)
10701void WebPageProxy::modelElementDidCreatePreview(const WebCore::ElementContext& context, const URL& url, const String& uuid, const FloatSize& size)
10702{
10703 modelElementController()->modelElementDidCreatePreview(context, url, uuid, size);
10704}
10705
10706void WebPageProxy::modelElementPreviewDidObtainContextId(const WebCore::ElementContext& context, const String& uuid, uint32_t contextId)
10707{
10708 if (hasRunningProcess())
10709 send(Messages::WebPage::ModelElementPreviewDidObtainContextId(context, uuid, contextId));
10710}
10711#endif
10712
10713#if !PLATFORM(COCOA)
10714SandboxExtension::HandleArray WebPageProxy::createNetworkExtensionsSandboxExtensions(WebProcessProxy& process)
10715{
10716 return SandboxExtension::HandleArray();
10717}
10718#endif
10719
10720#if ENABLE(MEDIA_SESSION_COORDINATOR)
10721void WebPageProxy::createMediaSessionCoordinator(Ref<MediaSessionCoordinatorProxyPrivate>&& privateCoordinator, CompletionHandler<void(bool)>&& completionHandler)
10722{
10723 sendWithAsyncReply(Messages::WebPage::CreateMediaSessionCoordinator(privateCoordinator->identifier()), [weakThis = makeWeakPtr(*this), privateCoordinator = WTFMove(privateCoordinator), completionHandler = WTFMove(completionHandler)](bool success) mutable {
10724
10725 if (!weakThis || !success) {
10726 completionHandler(false);
10727 return;
10728 }
10729
10730 weakThis->m_mediaSessionCoordinatorProxy = RemoteMediaSessionCoordinatorProxy::create(*weakThis, WTFMove(privateCoordinator));
10731 completionHandler(true);
10732 });
10733}
10734#endif
10735
10736#if PLATFORM(COCOA)
10737void WebPageProxy::appBoundNavigationData(CompletionHandler<void(const AppBoundNavigationTestingData&)>&& completionHandler)
10738{
10739 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::AppBoundNavigationData(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10740}
10741
10742void WebPageProxy::clearAppBoundNavigationData(CompletionHandler<void()>&& completionHandler)
10743{
10744 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::ClearAppBoundNavigationData(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10745}
10746#endif
10747
10748} // namespace WebKit
10749
10750#undef WEBPAGEPROXY_RELEASE_LOG
10751#undef WEBPAGEPROXY_RELEASE_LOG_ERROR
10752#undef MESSAGE_CHECK_COMPLETION
10753#undef MESSAGE_CHECK_URL
10754#undef MESSAGE_CHECK
10755#undef MERGE_WHEEL_EVENTS
10756